@opentermsarchive/engine 0.26.1 → 0.27.1
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/README.md +1 -3
- package/bin/ota-track.js +3 -3
- package/bin/ota-validate.js +2 -2
- package/bin/ota.js +1 -1
- package/config/default.json +1 -1
- package/package.json +3 -4
- package/scripts/dataset/export/index.js +4 -4
- package/scripts/dataset/export/index.test.js +11 -17
- package/scripts/declarations/lint/index.mocha.js +1 -1
- package/scripts/declarations/utils/index.js +12 -12
- package/scripts/declarations/validate/definitions.js +1 -1
- package/scripts/declarations/validate/index.mocha.js +30 -34
- package/scripts/declarations/validate/service.history.schema.js +11 -11
- package/scripts/declarations/validate/service.schema.js +13 -13
- package/scripts/history/migrate-services.js +4 -4
- package/scripts/history/update-to-full-hash.js +2 -2
- package/scripts/import/index.js +14 -14
- package/scripts/rewrite/rewrite-snapshots.js +3 -3
- package/scripts/rewrite/rewrite-versions.js +14 -14
- package/scripts/utils/renamer/README.md +3 -3
- package/scripts/utils/renamer/index.js +13 -13
- package/src/archivist/errors.js +1 -1
- package/src/archivist/extract/exports.js +3 -0
- package/src/archivist/{filter → extract}/index.js +23 -27
- package/src/archivist/extract/index.test.js +516 -0
- package/src/archivist/index.js +101 -140
- package/src/archivist/index.test.js +178 -166
- package/src/archivist/recorder/index.js +11 -55
- package/src/archivist/recorder/index.test.js +310 -356
- package/src/archivist/recorder/record.js +18 -7
- package/src/archivist/recorder/repositories/git/dataMapper.js +41 -31
- package/src/archivist/recorder/repositories/git/index.js +11 -15
- package/src/archivist/recorder/repositories/git/index.test.js +1058 -463
- package/src/archivist/recorder/repositories/interface.js +8 -6
- package/src/archivist/recorder/repositories/mongo/dataMapper.js +21 -14
- package/src/archivist/recorder/repositories/mongo/index.js +8 -8
- package/src/archivist/recorder/repositories/mongo/index.test.js +898 -479
- package/src/archivist/recorder/snapshot.js +5 -0
- package/src/archivist/recorder/snapshot.test.js +65 -0
- package/src/archivist/recorder/version.js +14 -0
- package/src/archivist/recorder/version.test.js +65 -0
- package/src/archivist/services/index.js +60 -51
- package/src/archivist/services/index.test.js +63 -83
- package/src/archivist/services/service.js +26 -22
- package/src/archivist/services/service.test.js +46 -68
- package/src/archivist/services/{pageDeclaration.js → sourceDocument.js} +11 -9
- package/src/archivist/services/{pageDeclaration.test.js → sourceDocument.test.js} +21 -21
- package/src/archivist/services/terms.js +26 -0
- package/src/archivist/services/{documentDeclaration.test.js → terms.test.js} +15 -15
- package/src/exports.js +2 -2
- package/src/index.js +16 -13
- package/src/logger/index.js +35 -36
- package/src/notifier/index.js +8 -8
- package/src/tracker/index.js +6 -6
- package/src/archivist/filter/exports.js +0 -3
- package/src/archivist/filter/index.test.js +0 -564
- package/src/archivist/recorder/record.test.js +0 -91
- package/src/archivist/services/documentDeclaration.js +0 -26
- /package/scripts/utils/renamer/rules/{documentTypes.json → termsTypes.json} +0 -0
- /package/scripts/utils/renamer/rules/{documentTypesByService.json → termsTypesByService.json} +0 -0
|
@@ -1,60 +1,64 @@
|
|
|
1
1
|
export default class Service {
|
|
2
|
-
|
|
2
|
+
terms = new Map();
|
|
3
3
|
|
|
4
4
|
constructor({ id, name }) {
|
|
5
5
|
this.id = id;
|
|
6
6
|
this.name = name;
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
if (!this.
|
|
9
|
+
getTerms(termsType, date) {
|
|
10
|
+
if (!this.terms[termsType]) {
|
|
11
11
|
return null;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
const { latest:
|
|
14
|
+
const { latest: currentlyValidTerms, history } = this.terms[termsType];
|
|
15
15
|
|
|
16
16
|
if (!date) {
|
|
17
|
-
return
|
|
17
|
+
return currentlyValidTerms;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
return (
|
|
21
21
|
history?.find(entry => new Date(date) <= new Date(entry.validUntil))
|
|
22
|
-
||
|
|
22
|
+
|| currentlyValidTerms
|
|
23
23
|
);
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
return Object.keys(this.
|
|
26
|
+
getTermsTypes() {
|
|
27
|
+
return Object.keys(this.terms);
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
if (!
|
|
32
|
-
|
|
30
|
+
addTerms(terms) {
|
|
31
|
+
if (!terms.service) {
|
|
32
|
+
terms.service = this;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
this.
|
|
35
|
+
this.terms[terms.type] = this.terms[terms.type] || {};
|
|
36
36
|
|
|
37
|
-
if (!
|
|
38
|
-
this.
|
|
37
|
+
if (!terms.validUntil) {
|
|
38
|
+
this.terms[terms.type].latest = terms;
|
|
39
39
|
|
|
40
40
|
return;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
this.
|
|
44
|
-
this.
|
|
45
|
-
this.
|
|
43
|
+
this.terms[terms.type].history = this.terms[terms.type].history || [];
|
|
44
|
+
this.terms[terms.type].history.push(terms);
|
|
45
|
+
this.terms[terms.type].history.sort((a, b) => new Date(a.validUntil) - new Date(b.validUntil));
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
getHistoryDates(
|
|
49
|
-
return this.
|
|
48
|
+
getHistoryDates(termsType) {
|
|
49
|
+
return this.terms[termsType].history.map(entry => entry.validUntil);
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
return this.
|
|
52
|
+
getNumberOfTerms() {
|
|
53
|
+
return this.getTermsTypes().length;
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
hasHistory() {
|
|
57
57
|
// If a service is loaded without its history it could return false even if a history declaration file exists.
|
|
58
|
-
return Boolean(Object.keys(this.
|
|
58
|
+
return Boolean(Object.keys(this.terms).find(termsType => this.terms[termsType].history));
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
static getNumberOfTerms(services, servicesIds) {
|
|
62
|
+
return servicesIds.reduce((acc, serviceId) => acc + services[serviceId].getNumberOfTerms(), 0);
|
|
59
63
|
}
|
|
60
64
|
}
|
|
@@ -1,135 +1,119 @@
|
|
|
1
1
|
import chai from 'chai';
|
|
2
2
|
|
|
3
|
-
import DocumentDeclaration from './documentDeclaration.js';
|
|
4
3
|
import Service from './service.js';
|
|
4
|
+
import Terms from './terms.js';
|
|
5
5
|
|
|
6
6
|
const { expect } = chai;
|
|
7
7
|
|
|
8
8
|
describe('Service', () => {
|
|
9
9
|
let subject;
|
|
10
|
-
const
|
|
10
|
+
const TERMS_TYPE = 'Terms of Service';
|
|
11
11
|
|
|
12
|
-
describe('#
|
|
13
|
-
let
|
|
12
|
+
describe('#addTerms', () => {
|
|
13
|
+
let terms;
|
|
14
14
|
|
|
15
15
|
before(async () => {
|
|
16
|
-
|
|
17
|
-
type:
|
|
16
|
+
terms = new Terms({
|
|
17
|
+
type: TERMS_TYPE,
|
|
18
18
|
service: subject,
|
|
19
|
-
pages: [{
|
|
20
|
-
location: 'https://www.service.example/tos',
|
|
21
|
-
contentSelectors: 'body',
|
|
22
|
-
}],
|
|
23
19
|
});
|
|
24
20
|
});
|
|
25
21
|
|
|
26
|
-
context('when
|
|
22
|
+
context('when terms declaration has no validity date', () => {
|
|
27
23
|
before(async () => {
|
|
28
24
|
subject = new Service({ id: 'serviceID', name: 'serviceName' });
|
|
29
|
-
subject.
|
|
25
|
+
subject.addTerms(terms);
|
|
30
26
|
});
|
|
31
27
|
|
|
32
|
-
it('adds the
|
|
33
|
-
expect(subject.
|
|
28
|
+
it('adds the terms as the last valid terms declaration', async () => {
|
|
29
|
+
expect(subject.getTerms(TERMS_TYPE)).to.deep.eql(terms);
|
|
34
30
|
});
|
|
35
31
|
});
|
|
36
32
|
|
|
37
|
-
context('when
|
|
38
|
-
let
|
|
33
|
+
context('when terms declaration has a validity date', () => {
|
|
34
|
+
let expiredTerms;
|
|
39
35
|
const VALIDITY_DATE = new Date('2020-07-22T11:30:21.000Z');
|
|
40
36
|
|
|
41
37
|
before(async () => {
|
|
42
38
|
subject = new Service({ id: 'serviceID', name: 'serviceName' });
|
|
43
|
-
|
|
44
|
-
type:
|
|
39
|
+
expiredTerms = new Terms({
|
|
40
|
+
type: TERMS_TYPE,
|
|
45
41
|
service: subject,
|
|
46
42
|
validUntil: VALIDITY_DATE,
|
|
47
|
-
pages: [{
|
|
48
|
-
location: 'https://www.service.example/terms',
|
|
49
|
-
contentSelectors: 'main',
|
|
50
|
-
}],
|
|
51
43
|
});
|
|
52
|
-
subject.
|
|
53
|
-
subject.
|
|
44
|
+
subject.addTerms(expiredTerms);
|
|
45
|
+
subject.addTerms(terms);
|
|
54
46
|
});
|
|
55
47
|
|
|
56
|
-
it('adds the
|
|
57
|
-
expect(subject.
|
|
48
|
+
it('adds the terms with the proper validity date', async () => {
|
|
49
|
+
expect(subject.getTerms(TERMS_TYPE, VALIDITY_DATE)).to.deep.eql(expiredTerms);
|
|
58
50
|
});
|
|
59
51
|
});
|
|
60
52
|
});
|
|
61
53
|
|
|
62
|
-
describe('#
|
|
54
|
+
describe('#getTerms', () => {
|
|
63
55
|
let subject;
|
|
64
56
|
|
|
65
|
-
const lastDeclaration = new
|
|
66
|
-
type: 'Terms of Service',
|
|
67
|
-
location: 'https://www.service.example/tos',
|
|
68
|
-
contentSelectors: 'body',
|
|
69
|
-
});
|
|
57
|
+
const lastDeclaration = new Terms({ type: TERMS_TYPE });
|
|
70
58
|
|
|
71
59
|
context('when there is no history', () => {
|
|
72
60
|
before(async () => {
|
|
73
61
|
subject = new Service({ id: 'serviceID', name: 'serviceName' });
|
|
74
|
-
subject.
|
|
62
|
+
subject.addTerms(lastDeclaration);
|
|
75
63
|
});
|
|
76
64
|
|
|
77
65
|
context('without given date', () => {
|
|
78
|
-
it('returns the last
|
|
79
|
-
expect(subject.
|
|
66
|
+
it('returns the last terms declaration', async () => {
|
|
67
|
+
expect(subject.getTerms(TERMS_TYPE)).to.eql(lastDeclaration);
|
|
80
68
|
});
|
|
81
69
|
});
|
|
82
70
|
|
|
83
71
|
context('with a date', () => {
|
|
84
|
-
it('returns the last
|
|
85
|
-
expect(subject.
|
|
72
|
+
it('returns the last terms declaration', async () => {
|
|
73
|
+
expect(subject.getTerms(TERMS_TYPE, '2020-08-21T11:30:21.000Z')).to.eql(lastDeclaration);
|
|
86
74
|
});
|
|
87
75
|
});
|
|
88
76
|
});
|
|
89
77
|
|
|
90
|
-
context('when the
|
|
91
|
-
const firstDeclaration = new
|
|
92
|
-
type:
|
|
93
|
-
location: 'https://www.service.example/terms',
|
|
94
|
-
contentSelectors: 'main',
|
|
78
|
+
context('when the terms have a history', () => {
|
|
79
|
+
const firstDeclaration = new Terms({
|
|
80
|
+
type: TERMS_TYPE,
|
|
95
81
|
validUntil: '2020-07-22T11:30:21.000Z',
|
|
96
82
|
});
|
|
97
83
|
|
|
98
|
-
const secondDeclaration = new
|
|
99
|
-
type:
|
|
100
|
-
location: 'https://www.service.example/terms-of-service',
|
|
101
|
-
contentSelectors: 'main',
|
|
84
|
+
const secondDeclaration = new Terms({
|
|
85
|
+
type: TERMS_TYPE,
|
|
102
86
|
validUntil: '2020-08-22T11:30:21.000Z',
|
|
103
87
|
});
|
|
104
88
|
|
|
105
89
|
before(async () => {
|
|
106
90
|
subject = new Service({ id: 'serviceID', name: 'serviceName' });
|
|
107
|
-
subject.
|
|
108
|
-
subject.
|
|
109
|
-
subject.
|
|
91
|
+
subject.addTerms(lastDeclaration);
|
|
92
|
+
subject.addTerms(firstDeclaration);
|
|
93
|
+
subject.addTerms(secondDeclaration);
|
|
110
94
|
});
|
|
111
95
|
|
|
112
96
|
context('without given date', () => {
|
|
113
|
-
it('returns the last
|
|
114
|
-
expect(subject.
|
|
97
|
+
it('returns the last terms declaration', async () => {
|
|
98
|
+
expect(subject.getTerms(TERMS_TYPE)).to.eql(lastDeclaration);
|
|
115
99
|
});
|
|
116
100
|
});
|
|
117
101
|
|
|
118
102
|
context('with a date', () => {
|
|
119
|
-
it('returns the
|
|
120
|
-
expect(subject.
|
|
103
|
+
it('returns the terms declaration according to the given date', async () => {
|
|
104
|
+
expect(subject.getTerms(TERMS_TYPE, '2020-08-21T11:30:21.000Z')).to.eql(secondDeclaration);
|
|
121
105
|
});
|
|
122
106
|
|
|
123
|
-
context('strictly equal to a
|
|
124
|
-
it('returns the
|
|
125
|
-
expect(subject.
|
|
107
|
+
context('strictly equal to a terms declaration validity date', () => {
|
|
108
|
+
it('returns the terms declaration with the validity date equal to the given date', async () => {
|
|
109
|
+
expect(subject.getTerms(TERMS_TYPE, secondDeclaration.validUntil)).to.eql(secondDeclaration);
|
|
126
110
|
});
|
|
127
111
|
});
|
|
128
112
|
});
|
|
129
113
|
});
|
|
130
114
|
});
|
|
131
115
|
|
|
132
|
-
describe('#
|
|
116
|
+
describe('#getTermsTypes', () => {
|
|
133
117
|
let subject;
|
|
134
118
|
let termsOfServiceDeclaration;
|
|
135
119
|
let privacyPolicyDeclaration;
|
|
@@ -137,25 +121,19 @@ describe('Service', () => {
|
|
|
137
121
|
before(async () => {
|
|
138
122
|
subject = new Service({ id: 'serviceID', name: 'serviceName' });
|
|
139
123
|
|
|
140
|
-
termsOfServiceDeclaration = new
|
|
141
|
-
type: 'Terms of Service',
|
|
142
|
-
location: 'https://www.service.example/tos',
|
|
143
|
-
contentSelectors: 'body',
|
|
144
|
-
});
|
|
124
|
+
termsOfServiceDeclaration = new Terms({ type: TERMS_TYPE });
|
|
145
125
|
|
|
146
|
-
privacyPolicyDeclaration = new
|
|
126
|
+
privacyPolicyDeclaration = new Terms({
|
|
147
127
|
type: 'Privacy Policy',
|
|
148
|
-
location: 'https://www.service.example/terms',
|
|
149
|
-
contentSelectors: 'main',
|
|
150
128
|
validUntil: '2020-07-22T11:30:21.000Z',
|
|
151
129
|
});
|
|
152
130
|
|
|
153
|
-
subject.
|
|
154
|
-
subject.
|
|
131
|
+
subject.addTerms(termsOfServiceDeclaration);
|
|
132
|
+
subject.addTerms(privacyPolicyDeclaration);
|
|
155
133
|
});
|
|
156
134
|
|
|
157
135
|
it('returns the service terms types', async () => {
|
|
158
|
-
expect(subject.
|
|
136
|
+
expect(subject.getTermsTypes()).to.have.members([
|
|
159
137
|
termsOfServiceDeclaration.type,
|
|
160
138
|
privacyPolicyDeclaration.type,
|
|
161
139
|
]);
|
|
@@ -1,19 +1,21 @@
|
|
|
1
|
-
export default class
|
|
2
|
-
constructor({ location, executeClientScripts, contentSelectors,
|
|
1
|
+
export default class SourceDocument {
|
|
2
|
+
constructor({ location, executeClientScripts, contentSelectors, insignificantContentSelectors, filters, content, mimeType }) {
|
|
3
3
|
this.location = location;
|
|
4
4
|
this.executeClientScripts = executeClientScripts;
|
|
5
5
|
this.contentSelectors = contentSelectors;
|
|
6
|
-
this.
|
|
6
|
+
this.insignificantContentSelectors = insignificantContentSelectors;
|
|
7
7
|
this.filters = filters;
|
|
8
|
+
this.content = content;
|
|
9
|
+
this.mimeType = mimeType;
|
|
8
10
|
this.id = new URL(location).pathname.split('/').filter(Boolean).join('-');
|
|
9
11
|
}
|
|
10
12
|
|
|
11
13
|
get cssSelectors() {
|
|
12
|
-
const { contentSelectors,
|
|
14
|
+
const { contentSelectors, insignificantContentSelectors } = this;
|
|
13
15
|
|
|
14
16
|
const result = [
|
|
15
|
-
...
|
|
16
|
-
...
|
|
17
|
+
...SourceDocument.extractCssSelectorsFromProperty(contentSelectors),
|
|
18
|
+
...SourceDocument.extractCssSelectorsFromProperty(insignificantContentSelectors),
|
|
17
19
|
];
|
|
18
20
|
|
|
19
21
|
return result.filter(selector => selector);
|
|
@@ -23,10 +25,10 @@ export default class PageDeclaration {
|
|
|
23
25
|
if (Array.isArray(property)) {
|
|
24
26
|
return []
|
|
25
27
|
.concat(property)
|
|
26
|
-
.flatMap(selector =>
|
|
28
|
+
.flatMap(selector => SourceDocument.extractCssSelectorsFromSelector(selector));
|
|
27
29
|
}
|
|
28
30
|
|
|
29
|
-
return
|
|
31
|
+
return SourceDocument.extractCssSelectorsFromSelector(property);
|
|
30
32
|
}
|
|
31
33
|
|
|
32
34
|
static extractCssSelectorsFromSelector(selector) {
|
|
@@ -43,7 +45,7 @@ export default class PageDeclaration {
|
|
|
43
45
|
return {
|
|
44
46
|
fetch: this.location,
|
|
45
47
|
select: this.contentSelectors,
|
|
46
|
-
remove: this.
|
|
48
|
+
remove: this.insignificantContentSelectors,
|
|
47
49
|
filter: this.filters ? this.filters.map(filter => filter.name) : undefined,
|
|
48
50
|
executeClientScripts: this.executeClientScripts,
|
|
49
51
|
};
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import chai from 'chai';
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
import SourceDocument from './sourceDocument.js';
|
|
4
4
|
|
|
5
5
|
const { expect } = chai;
|
|
6
6
|
|
|
7
|
-
describe('
|
|
7
|
+
describe('SourceDocument', () => {
|
|
8
8
|
const URL = 'https://www.service.example/terms';
|
|
9
9
|
|
|
10
10
|
describe('#getCssSelectors', () => {
|
|
11
11
|
context('with "select" property', () => {
|
|
12
12
|
context('with string selector', () => {
|
|
13
13
|
it('extracts selectors', async () => {
|
|
14
|
-
const result = new
|
|
14
|
+
const result = new SourceDocument({ location: URL, contentSelectors: 'body' }).cssSelectors;
|
|
15
15
|
|
|
16
16
|
expect(result).to.deep.equal(['body']);
|
|
17
17
|
});
|
|
@@ -19,7 +19,7 @@ describe('PageDeclaration', () => {
|
|
|
19
19
|
|
|
20
20
|
context('with range selector', () => {
|
|
21
21
|
it('extracts selectors', async () => {
|
|
22
|
-
const result = new
|
|
22
|
+
const result = new SourceDocument({
|
|
23
23
|
location: URL,
|
|
24
24
|
contentSelectors: {
|
|
25
25
|
startBefore: '#startBefore',
|
|
@@ -33,7 +33,7 @@ describe('PageDeclaration', () => {
|
|
|
33
33
|
|
|
34
34
|
context('with an array of mixed selectors', () => {
|
|
35
35
|
it('extracts selectors', async () => {
|
|
36
|
-
const result = new
|
|
36
|
+
const result = new SourceDocument({
|
|
37
37
|
location: URL,
|
|
38
38
|
contentSelectors: [
|
|
39
39
|
{
|
|
@@ -52,7 +52,7 @@ describe('PageDeclaration', () => {
|
|
|
52
52
|
context('with "remove" property', () => {
|
|
53
53
|
context('with string selector', () => {
|
|
54
54
|
it('extracts selectors', async () => {
|
|
55
|
-
const result = new
|
|
55
|
+
const result = new SourceDocument({ location: URL, insignificantContentSelectors: 'body' }).cssSelectors;
|
|
56
56
|
|
|
57
57
|
expect(result).to.deep.equal(['body']);
|
|
58
58
|
});
|
|
@@ -60,9 +60,9 @@ describe('PageDeclaration', () => {
|
|
|
60
60
|
|
|
61
61
|
context('with range selector', () => {
|
|
62
62
|
it('extracts selectors', async () => {
|
|
63
|
-
const result = new
|
|
63
|
+
const result = new SourceDocument({
|
|
64
64
|
location: URL,
|
|
65
|
-
|
|
65
|
+
insignificantContentSelectors: {
|
|
66
66
|
startBefore: '#startBefore',
|
|
67
67
|
endBefore: '#endBefore',
|
|
68
68
|
},
|
|
@@ -74,9 +74,9 @@ describe('PageDeclaration', () => {
|
|
|
74
74
|
|
|
75
75
|
context('with an array of mixed selectors', () => {
|
|
76
76
|
it('extracts selectors', async () => {
|
|
77
|
-
const result = new
|
|
77
|
+
const result = new SourceDocument({
|
|
78
78
|
location: URL,
|
|
79
|
-
|
|
79
|
+
insignificantContentSelectors: [
|
|
80
80
|
{
|
|
81
81
|
startBefore: '#startBefore',
|
|
82
82
|
endBefore: '#endBefore',
|
|
@@ -93,10 +93,10 @@ describe('PageDeclaration', () => {
|
|
|
93
93
|
context('with both "select" and "remove" property', () => {
|
|
94
94
|
context('with string selector', () => {
|
|
95
95
|
it('extracts selectors', async () => {
|
|
96
|
-
const result = new
|
|
96
|
+
const result = new SourceDocument({
|
|
97
97
|
location: URL,
|
|
98
98
|
contentSelectors: 'body',
|
|
99
|
-
|
|
99
|
+
insignificantContentSelectors: 'h1',
|
|
100
100
|
}).cssSelectors;
|
|
101
101
|
|
|
102
102
|
expect(result).to.deep.equal([ 'body', 'h1' ]);
|
|
@@ -105,13 +105,13 @@ describe('PageDeclaration', () => {
|
|
|
105
105
|
|
|
106
106
|
context('with range selector', () => {
|
|
107
107
|
it('extracts selectors', async () => {
|
|
108
|
-
const result = new
|
|
108
|
+
const result = new SourceDocument({
|
|
109
109
|
location: URL,
|
|
110
110
|
contentSelectors: {
|
|
111
111
|
startBefore: '#startBefore',
|
|
112
112
|
endBefore: '#endBefore',
|
|
113
113
|
},
|
|
114
|
-
|
|
114
|
+
insignificantContentSelectors: {
|
|
115
115
|
startBefore: '#startBefore',
|
|
116
116
|
endBefore: '#endBefore',
|
|
117
117
|
},
|
|
@@ -128,7 +128,7 @@ describe('PageDeclaration', () => {
|
|
|
128
128
|
|
|
129
129
|
context('with an array of mixed selectors', () => {
|
|
130
130
|
it('extracts selectors', async () => {
|
|
131
|
-
const result = new
|
|
131
|
+
const result = new SourceDocument({
|
|
132
132
|
location: URL,
|
|
133
133
|
contentSelectors: [
|
|
134
134
|
{
|
|
@@ -137,7 +137,7 @@ describe('PageDeclaration', () => {
|
|
|
137
137
|
},
|
|
138
138
|
'body',
|
|
139
139
|
],
|
|
140
|
-
|
|
140
|
+
insignificantContentSelectors: [
|
|
141
141
|
{
|
|
142
142
|
startBefore: '#startBefore',
|
|
143
143
|
endBefore: '#endBefore',
|
|
@@ -160,8 +160,8 @@ describe('PageDeclaration', () => {
|
|
|
160
160
|
});
|
|
161
161
|
|
|
162
162
|
describe('#toPersistence', () => {
|
|
163
|
-
it('converts basic
|
|
164
|
-
const result = new
|
|
163
|
+
it('converts basic source document declarations into JSON representation', async () => {
|
|
164
|
+
const result = new SourceDocument({
|
|
165
165
|
location: URL,
|
|
166
166
|
contentSelectors: 'body',
|
|
167
167
|
}).toPersistence();
|
|
@@ -177,8 +177,8 @@ describe('PageDeclaration', () => {
|
|
|
177
177
|
expect(result).to.deep.equal(expectedResult);
|
|
178
178
|
});
|
|
179
179
|
|
|
180
|
-
it('converts
|
|
181
|
-
const result = new
|
|
180
|
+
it('converts full source document declarations to JSON representation', async () => {
|
|
181
|
+
const result = new SourceDocument({
|
|
182
182
|
location: URL,
|
|
183
183
|
contentSelectors: [
|
|
184
184
|
{
|
|
@@ -187,7 +187,7 @@ describe('PageDeclaration', () => {
|
|
|
187
187
|
},
|
|
188
188
|
'body',
|
|
189
189
|
],
|
|
190
|
-
|
|
190
|
+
insignificantContentSelectors: [
|
|
191
191
|
{
|
|
192
192
|
startBefore: '#startBefore',
|
|
193
193
|
endBefore: '#endBefore',
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export default class Terms {
|
|
2
|
+
constructor({ service, type, sourceDocuments, validUntil }) {
|
|
3
|
+
this.service = service;
|
|
4
|
+
this.type = type;
|
|
5
|
+
this.sourceDocuments = sourceDocuments;
|
|
6
|
+
|
|
7
|
+
if (validUntil) {
|
|
8
|
+
this.validUntil = validUntil;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
get hasMultipleSourceDocuments() {
|
|
13
|
+
return this.sourceDocuments.length > 1;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
toPersistence() {
|
|
17
|
+
return {
|
|
18
|
+
name: this.service.name,
|
|
19
|
+
documents: {
|
|
20
|
+
[this.type]: this.hasMultipleSourceDocuments
|
|
21
|
+
? { combine: this.sourceDocuments.map(sourceDocument => sourceDocument.toPersistence()) }
|
|
22
|
+
: this.sourceDocuments[0].toPersistence(),
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import chai from 'chai';
|
|
2
2
|
|
|
3
|
-
import
|
|
4
|
-
import
|
|
3
|
+
import SourceDocument from './sourceDocument.js';
|
|
4
|
+
import Terms from './terms.js';
|
|
5
5
|
|
|
6
6
|
const { expect } = chai;
|
|
7
7
|
|
|
8
|
-
describe('
|
|
8
|
+
describe('Terms', () => {
|
|
9
9
|
const service = { name: 'Service' };
|
|
10
|
-
const
|
|
10
|
+
const termsType = 'Terms of Service';
|
|
11
11
|
const URL = 'https://www.service.example/terms';
|
|
12
|
-
const
|
|
12
|
+
const document1 = new SourceDocument({
|
|
13
13
|
location: URL,
|
|
14
14
|
contentSelectors: [
|
|
15
15
|
{
|
|
@@ -18,7 +18,7 @@ describe('DocumentDeclaration', () => {
|
|
|
18
18
|
},
|
|
19
19
|
'body',
|
|
20
20
|
],
|
|
21
|
-
|
|
21
|
+
insignificantContentSelectors: [
|
|
22
22
|
{
|
|
23
23
|
startBefore: '#startBefore',
|
|
24
24
|
endBefore: '#endBefore',
|
|
@@ -26,7 +26,7 @@ describe('DocumentDeclaration', () => {
|
|
|
26
26
|
'body',
|
|
27
27
|
],
|
|
28
28
|
});
|
|
29
|
-
const
|
|
29
|
+
const document1AsJSON = {
|
|
30
30
|
fetch: URL,
|
|
31
31
|
select: [
|
|
32
32
|
{
|
|
@@ -46,12 +46,12 @@ describe('DocumentDeclaration', () => {
|
|
|
46
46
|
executeClientScripts: undefined,
|
|
47
47
|
};
|
|
48
48
|
|
|
49
|
-
const
|
|
49
|
+
const document2 = new SourceDocument({
|
|
50
50
|
location: URL,
|
|
51
51
|
contentSelectors: 'body',
|
|
52
52
|
});
|
|
53
53
|
|
|
54
|
-
const
|
|
54
|
+
const document2AsJSON = {
|
|
55
55
|
fetch: URL,
|
|
56
56
|
select: 'body',
|
|
57
57
|
remove: undefined,
|
|
@@ -60,23 +60,23 @@ describe('DocumentDeclaration', () => {
|
|
|
60
60
|
};
|
|
61
61
|
|
|
62
62
|
describe('#toPersistence', () => {
|
|
63
|
-
it('converts
|
|
64
|
-
const result = new
|
|
63
|
+
it('converts terms with single source document to JSON representation', async () => {
|
|
64
|
+
const result = new Terms({ service, type: termsType, sourceDocuments: [document1] }).toPersistence();
|
|
65
65
|
|
|
66
66
|
const expectedResult = {
|
|
67
67
|
name: service.name,
|
|
68
|
-
documents: { [
|
|
68
|
+
documents: { [termsType]: document1AsJSON },
|
|
69
69
|
};
|
|
70
70
|
|
|
71
71
|
expect(result).to.deep.equal(expectedResult);
|
|
72
72
|
});
|
|
73
73
|
|
|
74
|
-
it('converts
|
|
75
|
-
const result = new
|
|
74
|
+
it('converts terms with multiple source documents to JSON representation', async () => {
|
|
75
|
+
const result = new Terms({ service, type: termsType, sourceDocuments: [ document1, document2 ] }).toPersistence();
|
|
76
76
|
|
|
77
77
|
const expectedResult = {
|
|
78
78
|
name: service.name,
|
|
79
|
-
documents: { [
|
|
79
|
+
documents: { [termsType]: { combine: [ document1AsJSON, document2AsJSON ] } },
|
|
80
80
|
};
|
|
81
81
|
|
|
82
82
|
expect(result).to.deep.equal(expectedResult);
|
package/src/exports.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { default as
|
|
2
|
-
export { default as
|
|
1
|
+
export { default as sourceDocument } from './archivist/services/sourceDocument.js';
|
|
2
|
+
export { default as extract } from './archivist/extract/exports.js';
|
|
3
3
|
export { default as fetch } from './archivist/fetcher/exports.js';
|