@contrail/cli 3.5.1-alpha.68d57e0 → 3.5.1-alpha.9da7ac5
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 -1
- package/node_modules/@contrail/loader/lib/color-processor.js +23 -9
- package/node_modules/@contrail/loader/lib/color-processor.spec.js +62 -112
- package/node_modules/@contrail/loader/lib/common/chunk-by-url-length.d.ts +1 -1
- package/node_modules/@contrail/loader/lib/common/chunk-by-url-length.js +0 -2
- package/node_modules/@contrail/loader/lib/common/chunk-by-url-length.spec.js +0 -4
- package/node_modules/@contrail/loader/lib/common/size-range-helpers.js +1 -0
- package/node_modules/@contrail/loader/lib/constants.d.ts +3 -0
- package/node_modules/@contrail/loader/lib/constants.js +4 -1
- package/node_modules/@contrail/loader/lib/entities-v2/colors-v2/color-processor-v2.js +23 -9
- package/node_modules/@contrail/loader/lib/entities-v2/colors-v2/color-processor-v2.spec.js +62 -112
- package/node_modules/@contrail/loader/lib/entities-v2/entities-helper.js +1 -0
- package/node_modules/@contrail/loader/lib/entities-v2/linesheet-v2/assortment-processor.js +1 -0
- package/node_modules/@contrail/loader/lib/entities-v2/linesheet-v2/item-processor.js +22 -8
- package/node_modules/@contrail/loader/lib/entities-v2/linesheet-v2/item-processor.spec.js +1 -43
- package/node_modules/@contrail/loader/lib/pipeline/item-execute-helpers.js +3 -77
- package/node_modules/@contrail/loader/lib/pipeline/item-execute-helpers.spec.js +0 -82
- package/node_modules/@contrail/loader/lib/pipeline/preview.js +5 -0
- package/node_modules/@contrail/loader/lib/pipeline/preview.spec.js +2 -2
- package/node_modules/@contrail/loader/lib/pipeline/project-item-execute-helpers.js +1 -1
- package/node_modules/@contrail/loader/lib/pipeline/transform.js +0 -18
- package/node_modules/@contrail/loader/lib/pipeline/transform.spec.js +2 -3
- package/node_modules/@contrail/loader/lib/pipeline/types.d.ts +2 -5
- package/node_modules/@contrail/loader/lib/pipeline/types.js +0 -2
- package/node_modules/@contrail/loader/lib/pipeline/validate.js +437 -184
- package/node_modules/@contrail/loader/lib/pipeline/validate.spec.js +53 -157
- package/node_modules/@contrail/loader/package.json +2 -3
- package/oclif.manifest.json +1 -1
- package/package.json +2 -2
- package/node_modules/@contrail/loader/lib/common/color-validation.d.ts +0 -26
- package/node_modules/@contrail/loader/lib/common/color-validation.js +0 -163
- package/node_modules/@contrail/loader/lib/common/color-validation.spec.d.ts +0 -1
- package/node_modules/@contrail/loader/lib/common/color-validation.spec.js +0 -102
- package/node_modules/@contrail/loader/lib/pipeline/identifier-resolver.d.ts +0 -5
- package/node_modules/@contrail/loader/lib/pipeline/identifier-resolver.js +0 -562
- package/node_modules/@contrail/loader/lib/pipeline/identifier-resolver.spec.d.ts +0 -1
- package/node_modules/@contrail/loader/lib/pipeline/identifier-resolver.spec.js +0 -231
- package/node_modules/validate-color/LICENSE +0 -21
- package/node_modules/validate-color/README.md +0 -265
- package/node_modules/validate-color/lib/index.d.ts +0 -10
- package/node_modules/validate-color/lib/index.js +0 -1
- package/node_modules/validate-color/package.json +0 -91
- package/node_modules/validate-color/test/redos.js +0 -29
|
@@ -1,231 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const identifier_resolver_1 = require("./identifier-resolver");
|
|
4
|
-
const types_1 = require("./types");
|
|
5
|
-
describe('resolveIdentifiers', () => {
|
|
6
|
-
describe('validateAssortmentColumns', () => {
|
|
7
|
-
it('skips for non-ASSORTMENT loads', async () => {
|
|
8
|
-
const config = { loadType: [types_1.LoadType.ITEM] };
|
|
9
|
-
const rows = [{ itemFamilyFederatedId: 'fam-1', name: 'A' }];
|
|
10
|
-
const { issues } = await (0, identifier_resolver_1.resolveIdentifiers)(rows, config);
|
|
11
|
-
const assortmentIssue = issues.find((i) => i.columnName?.includes('assortmentId'));
|
|
12
|
-
expect(assortmentIssue).toBeUndefined();
|
|
13
|
-
});
|
|
14
|
-
it('errors when no rows have assortmentId or assortmentIdentifier', async () => {
|
|
15
|
-
const config = { loadType: [types_1.LoadType.ASSORTMENT] };
|
|
16
|
-
const rows = [{ itemFamilyFederatedId: 'fam-1', name: 'A' }];
|
|
17
|
-
const { issues } = await (0, identifier_resolver_1.resolveIdentifiers)(rows, config);
|
|
18
|
-
const issue = issues.find((i) => i.message.includes('ASSORTMENT loads require'));
|
|
19
|
-
expect(issue).toBeDefined();
|
|
20
|
-
});
|
|
21
|
-
it('errors when rows have both assortmentId and assortmentIdentifier', async () => {
|
|
22
|
-
const config = { loadType: [types_1.LoadType.ASSORTMENT] };
|
|
23
|
-
const rows = [{ itemFamilyFederatedId: 'fam-1', name: 'A', assortmentId: 'id-1', assortmentIdentifier: 'ident-1' }];
|
|
24
|
-
const { issues } = await (0, identifier_resolver_1.resolveIdentifiers)(rows, config);
|
|
25
|
-
const issue = issues.find((i) => i.message.includes('both "assortmentId" and "assortmentIdentifier"'));
|
|
26
|
-
expect(issue).toBeDefined();
|
|
27
|
-
});
|
|
28
|
-
it('errors when assortmentId values are empty', async () => {
|
|
29
|
-
const config = { loadType: [types_1.LoadType.ASSORTMENT] };
|
|
30
|
-
const rows = [{ itemFamilyFederatedId: 'fam-1', name: 'A', assortmentId: '' }];
|
|
31
|
-
const { issues } = await (0, identifier_resolver_1.resolveIdentifiers)(rows, config);
|
|
32
|
-
const issue = issues.find((i) => i.message.includes('"assortmentId" cannot be empty'));
|
|
33
|
-
expect(issue).toBeDefined();
|
|
34
|
-
});
|
|
35
|
-
it('does not error when rows have valid assortmentId (no client)', async () => {
|
|
36
|
-
const config = { loadType: [types_1.LoadType.ASSORTMENT] };
|
|
37
|
-
const rows = [{ itemFamilyFederatedId: 'fam-1', name: 'A', assortmentId: 'assort-1' }];
|
|
38
|
-
const { issues } = await (0, identifier_resolver_1.resolveIdentifiers)(rows, config);
|
|
39
|
-
const columnIssue = issues.find((i) => i.message.includes('ASSORTMENT loads require'));
|
|
40
|
-
expect(columnIssue).toBeUndefined();
|
|
41
|
-
});
|
|
42
|
-
it('does not error on rows missing assortmentId when derived from conditional columns with conditions', async () => {
|
|
43
|
-
const config = {
|
|
44
|
-
loadType: [types_1.LoadType.ASSORTMENT],
|
|
45
|
-
conditionalColumns: [
|
|
46
|
-
{ toProperty: 'assortmentId', conditions: [{ conditional: "{gender} === 'mens'", value: 'assort-1' }] },
|
|
47
|
-
],
|
|
48
|
-
};
|
|
49
|
-
const rows = [
|
|
50
|
-
{ itemFamilyFederatedId: 'fam-1', name: 'A', assortmentId: 'assort-1' },
|
|
51
|
-
{ itemFamilyFederatedId: 'fam-2', name: 'B' },
|
|
52
|
-
];
|
|
53
|
-
const { issues } = await (0, identifier_resolver_1.resolveIdentifiers)(rows, config);
|
|
54
|
-
const emptyIssue = issues.find((i) => i.message.includes('"assortmentId" cannot be empty'));
|
|
55
|
-
expect(emptyIssue).toBeUndefined();
|
|
56
|
-
});
|
|
57
|
-
});
|
|
58
|
-
describe('combo mode: PROJECT_ITEM + ASSORTMENT', () => {
|
|
59
|
-
const buildClient = (handler) => ({
|
|
60
|
-
get: jest.fn(async (params) => handler(params)),
|
|
61
|
-
create: jest.fn(),
|
|
62
|
-
update: jest.fn(),
|
|
63
|
-
delete: jest.fn(),
|
|
64
|
-
batchCreate: jest.fn(),
|
|
65
|
-
batchUpdate: jest.fn(),
|
|
66
|
-
batchDelete: jest.fn(),
|
|
67
|
-
getAllReferences: jest.fn(),
|
|
68
|
-
});
|
|
69
|
-
it('stamps projectId on rows from the assortment workspace when assortmentId is per-row', async () => {
|
|
70
|
-
const config = { loadType: [types_1.LoadType.PROJECT_ITEM, types_1.LoadType.ASSORTMENT] };
|
|
71
|
-
const rows = [
|
|
72
|
-
{ itemFamilyFederatedId: 'fam-1', name: 'A', assortmentId: 'assort-1' },
|
|
73
|
-
{ itemFamilyFederatedId: 'fam-2', name: 'B', assortmentId: 'assort-1' },
|
|
74
|
-
];
|
|
75
|
-
const client = buildClient((params) => {
|
|
76
|
-
if (params.entityName === 'assortment' && params.id === 'assort-1') {
|
|
77
|
-
return { id: 'assort-1', name: 'Assort 1', workspaceId: 'ws-1' };
|
|
78
|
-
}
|
|
79
|
-
if (params.entityName === 'workspace' && params.id === 'ws-1') {
|
|
80
|
-
return { id: 'ws-1', project: { id: 'proj-1', name: 'Project 1' } };
|
|
81
|
-
}
|
|
82
|
-
return undefined;
|
|
83
|
-
});
|
|
84
|
-
const { issues } = await (0, identifier_resolver_1.resolveIdentifiers)(rows, config, client);
|
|
85
|
-
expect(issues).toHaveLength(0);
|
|
86
|
-
expect(rows[0].projectId).toBe('proj-1');
|
|
87
|
-
expect(rows[1].projectId).toBe('proj-1');
|
|
88
|
-
expect(rows[0].projectName).toBe('Project 1');
|
|
89
|
-
expect(rows[0].assortmentWorkspaceId).toBe('ws-1');
|
|
90
|
-
});
|
|
91
|
-
it('resolves assortmentIdentifier → assortment → workspace → project', async () => {
|
|
92
|
-
const config = { loadType: [types_1.LoadType.PROJECT_ITEM, types_1.LoadType.ASSORTMENT] };
|
|
93
|
-
const rows = [
|
|
94
|
-
{ itemFamilyFederatedId: 'fam-1', name: 'A', assortmentIdentifier: 'NORD-2026' },
|
|
95
|
-
];
|
|
96
|
-
const client = buildClient((params) => {
|
|
97
|
-
if (params.entityName === 'assortment' && params.criteria?.identifier === 'NORD-2026') {
|
|
98
|
-
return [{ id: 'assort-9', name: 'Nord 2026', workspaceId: 'ws-9' }];
|
|
99
|
-
}
|
|
100
|
-
if (params.entityName === 'workspace' && params.id === 'ws-9') {
|
|
101
|
-
return { id: 'ws-9', project: { id: 'proj-9', name: 'Nord Project' } };
|
|
102
|
-
}
|
|
103
|
-
return undefined;
|
|
104
|
-
});
|
|
105
|
-
const { issues } = await (0, identifier_resolver_1.resolveIdentifiers)(rows, config, client);
|
|
106
|
-
expect(issues).toHaveLength(0);
|
|
107
|
-
expect(rows[0].assortmentId).toBe('assort-9');
|
|
108
|
-
expect(rows[0].projectId).toBe('proj-9');
|
|
109
|
-
expect(rows[0].projectName).toBe('Nord Project');
|
|
110
|
-
expect(rows[0].assortmentIdentifier).toBeUndefined();
|
|
111
|
-
});
|
|
112
|
-
it('reports assortment-only error when a row is missing assortmentId (no project/workspace mention)', async () => {
|
|
113
|
-
const config = { loadType: [types_1.LoadType.PROJECT_ITEM, types_1.LoadType.ASSORTMENT] };
|
|
114
|
-
const rows = [
|
|
115
|
-
{ itemFamilyFederatedId: 'fam-1', name: 'A' },
|
|
116
|
-
];
|
|
117
|
-
const { issues } = await (0, identifier_resolver_1.resolveIdentifiers)(rows, config);
|
|
118
|
-
const projectIssue = issues.find((i) => i.message.includes('workspaceIdentifier') || i.message.includes('projectId'));
|
|
119
|
-
expect(projectIssue).toBeUndefined();
|
|
120
|
-
const assortmentIssue = issues.find((i) => i.message.includes('ASSORTMENT loads require'));
|
|
121
|
-
expect(assortmentIssue).toBeDefined();
|
|
122
|
-
});
|
|
123
|
-
it('errors when the assortment has no workspaceId (assortment-scoped error)', async () => {
|
|
124
|
-
const config = { loadType: [types_1.LoadType.PROJECT_ITEM, types_1.LoadType.ASSORTMENT] };
|
|
125
|
-
const rows = [
|
|
126
|
-
{ itemFamilyFederatedId: 'fam-1', name: 'A', assortmentId: 'assort-x' },
|
|
127
|
-
];
|
|
128
|
-
const client = buildClient((params) => {
|
|
129
|
-
if (params.entityName === 'assortment' && params.id === 'assort-x') {
|
|
130
|
-
return { id: 'assort-x', name: 'X' };
|
|
131
|
-
}
|
|
132
|
-
return undefined;
|
|
133
|
-
});
|
|
134
|
-
const { issues } = await (0, identifier_resolver_1.resolveIdentifiers)(rows, config, client);
|
|
135
|
-
const issue = issues.find((i) => i.message.includes('has no workspaceId'));
|
|
136
|
-
expect(issue).toBeDefined();
|
|
137
|
-
expect(issue?.columnName).toBe('assortmentId');
|
|
138
|
-
});
|
|
139
|
-
it('errors when the assortment workspace has no project relation', async () => {
|
|
140
|
-
const config = { loadType: [types_1.LoadType.PROJECT_ITEM, types_1.LoadType.ASSORTMENT] };
|
|
141
|
-
const rows = [
|
|
142
|
-
{ itemFamilyFederatedId: 'fam-1', name: 'A', assortmentId: 'assort-y' },
|
|
143
|
-
];
|
|
144
|
-
const client = buildClient((params) => {
|
|
145
|
-
if (params.entityName === 'assortment' && params.id === 'assort-y') {
|
|
146
|
-
return { id: 'assort-y', name: 'Y', workspaceId: 'ws-y' };
|
|
147
|
-
}
|
|
148
|
-
if (params.entityName === 'workspace' && params.id === 'ws-y') {
|
|
149
|
-
return { id: 'ws-y' };
|
|
150
|
-
}
|
|
151
|
-
return undefined;
|
|
152
|
-
});
|
|
153
|
-
const { issues } = await (0, identifier_resolver_1.resolveIdentifiers)(rows, config, client);
|
|
154
|
-
const issue = issues.find((i) => i.message.includes('has no associated project'));
|
|
155
|
-
expect(issue).toBeDefined();
|
|
156
|
-
expect(issue?.columnName).toBe('assortmentId');
|
|
157
|
-
expect(rows[0].projectId).toBeUndefined();
|
|
158
|
-
});
|
|
159
|
-
it('does not require workspaceIdentifier or projectId on rows in combo mode', async () => {
|
|
160
|
-
const config = { loadType: [types_1.LoadType.PROJECT_ITEM, types_1.LoadType.ASSORTMENT] };
|
|
161
|
-
const rows = [
|
|
162
|
-
{ itemFamilyFederatedId: 'fam-1', name: 'A', assortmentId: 'assort-1' },
|
|
163
|
-
];
|
|
164
|
-
const { issues } = await (0, identifier_resolver_1.resolveIdentifiers)(rows, config);
|
|
165
|
-
const projectItemIssue = issues.find((i) => i.message.includes('PROJECT_ITEM loads require'));
|
|
166
|
-
expect(projectItemIssue).toBeUndefined();
|
|
167
|
-
});
|
|
168
|
-
it('does NOT trigger combo mode when rows already have a workspaceIdentifier', async () => {
|
|
169
|
-
const config = { loadType: [types_1.LoadType.PROJECT_ITEM, types_1.LoadType.ASSORTMENT] };
|
|
170
|
-
const rows = [
|
|
171
|
-
{
|
|
172
|
-
itemFamilyFederatedId: 'fam-1',
|
|
173
|
-
name: 'A',
|
|
174
|
-
assortmentId: 'assort-1',
|
|
175
|
-
workspaceIdentifier: 'project_one',
|
|
176
|
-
},
|
|
177
|
-
];
|
|
178
|
-
const client = buildClient((params) => {
|
|
179
|
-
if (params.entityName === 'workspace' && params.criteria?.identifier === 'project_one') {
|
|
180
|
-
return [{ id: 'ws-1' }];
|
|
181
|
-
}
|
|
182
|
-
if (params.entityName === 'workspace' && params.id === 'ws-1') {
|
|
183
|
-
return { id: 'ws-1', project: { id: 'proj-1', name: 'Project 1' } };
|
|
184
|
-
}
|
|
185
|
-
if (params.entityName === 'assortment' && params.id === 'assort-1') {
|
|
186
|
-
return { id: 'assort-1', name: 'A1', workspaceId: 'totally-bogus-id' };
|
|
187
|
-
}
|
|
188
|
-
return undefined;
|
|
189
|
-
});
|
|
190
|
-
const { issues } = await (0, identifier_resolver_1.resolveIdentifiers)(rows, config, client);
|
|
191
|
-
expect(issues).toHaveLength(0);
|
|
192
|
-
expect(rows[0].projectId).toBe('proj-1');
|
|
193
|
-
expect(rows[0].workspaceIdentifier).toBeUndefined();
|
|
194
|
-
});
|
|
195
|
-
it('does NOT trigger combo mode when rows already have a projectId', async () => {
|
|
196
|
-
const config = { loadType: [types_1.LoadType.PROJECT_ITEM, types_1.LoadType.ASSORTMENT] };
|
|
197
|
-
const rows = [
|
|
198
|
-
{
|
|
199
|
-
itemFamilyFederatedId: 'fam-1',
|
|
200
|
-
name: 'A',
|
|
201
|
-
assortmentId: 'assort-1',
|
|
202
|
-
projectId: 'proj-explicit',
|
|
203
|
-
},
|
|
204
|
-
];
|
|
205
|
-
const client = buildClient((params) => {
|
|
206
|
-
if (params.entityName === 'project' && params.id === 'proj-explicit') {
|
|
207
|
-
return { id: 'proj-explicit', name: 'Explicit Project' };
|
|
208
|
-
}
|
|
209
|
-
if (params.entityName === 'assortment' && params.id === 'assort-1') {
|
|
210
|
-
return { id: 'assort-1', name: 'A1', workspaceId: 'totally-bogus-id' };
|
|
211
|
-
}
|
|
212
|
-
return undefined;
|
|
213
|
-
});
|
|
214
|
-
const { issues } = await (0, identifier_resolver_1.resolveIdentifiers)(rows, config, client);
|
|
215
|
-
expect(issues).toHaveLength(0);
|
|
216
|
-
expect(rows[0].projectId).toBe('proj-explicit');
|
|
217
|
-
expect(rows[0].projectName).toBe('Explicit Project');
|
|
218
|
-
});
|
|
219
|
-
});
|
|
220
|
-
describe('PROJECT_ITEM-only loads (no assortment)', () => {
|
|
221
|
-
it('still requires workspaceIdentifier or projectId on rows', async () => {
|
|
222
|
-
const config = { loadType: [types_1.LoadType.PROJECT_ITEM] };
|
|
223
|
-
const rows = [
|
|
224
|
-
{ itemFamilyFederatedId: 'fam-1', name: 'A' },
|
|
225
|
-
];
|
|
226
|
-
const { issues } = await (0, identifier_resolver_1.resolveIdentifiers)(rows, config);
|
|
227
|
-
const issue = issues.find((i) => i.message.includes('PROJECT_ITEM loads require'));
|
|
228
|
-
expect(issue).toBeDefined();
|
|
229
|
-
});
|
|
230
|
-
});
|
|
231
|
-
});
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
The MIT License (MIT)
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2018 Wallace Sidhrée
|
|
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 all
|
|
13
|
-
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 THE
|
|
21
|
-
SOFTWARE.
|
|
@@ -1,265 +0,0 @@
|
|
|
1
|
-

|
|
2
|
-
|
|
3
|
-
# Validate Color
|
|
4
|
-
|
|
5
|
-
> ✅🌈🙌 Validate HTML colors by `name`, `special name`, `hex`, `rgb`, `rgba`, `hsl`, `hsla`, `hwb`, `lab` or `lch` values
|
|
6
|
-
|
|
7
|
-
[](https://travis-ci.org/dreamyguy/validate-color) [](https://github.com/nodejs/node/releases/tag/v12.4.0)
|
|
8
|
-
[](https://github.com/npm/cli/releases/tag/v6.9.0)
|
|
9
|
-
[](https://github.com/dreamyguy/validate-color/blob/master/LICENSE)
|
|
10
|
-
|
|
11
|
-
**_HTML colors are remarkably easy to get wrong_**, because they allow for so many different values.
|
|
12
|
-
|
|
13
|
-
As I was writing [Console Log Plus](https://github.com/dreamyguy/console-log-plus), I thought it would be great to allow users to pass any _HTML color_ they wanted as one of the parameter to the function. But since _HTML colors_ have so many variations and therefore are complex strings, it didn't take me long to realize that I'd have to make quite a few checks to validate the value passed by the user. That need brought me here.
|
|
14
|
-
|
|
15
|
-
**Validate Color** let's one validate the color string against all current possible _HTML color_ values. Some examples:
|
|
16
|
-
|
|
17
|
-
- `hex` - `#bada55`
|
|
18
|
-
- `name` - `LightGoldenrodYellow`
|
|
19
|
-
- `special name` - `currentColor`
|
|
20
|
-
- `rgb` - `rgb(0 0 0)`
|
|
21
|
-
- `rgba` - `rgba(0, 0, 0, .45)`
|
|
22
|
-
- `hsl` - `hsl(4.71239rad, 60%, 70%)`
|
|
23
|
-
- `hsla` - `hsla(180deg 100% 50% / .8)`
|
|
24
|
-
- `hwb` - `hwb(180deg 0% 0% / 100%)`
|
|
25
|
-
- `lab` - `lab(2000.1337% -8.6911 -159.131231 / .987189732)`
|
|
26
|
-
- `lch` - `lch(54.292% 106.839 40.853)`
|
|
27
|
-
|
|
28
|
-
Both `rgba` and `hsla` are now officially merged into their `rgb` and `hsl` counterparts, so the `a` can be omitted. The `a` is considered legacy syntax, so it will still work.
|
|
29
|
-
|
|
30
|
-
# Demo ✅ 🌈 🙌
|
|
31
|
-
|
|
32
|
-
To demonstrate the power of _validate-color_, I decided it would be best to create a living github page, that would serve both as a way of showcase _validate-color_, and facilitate its use:
|
|
33
|
-
|
|
34
|
-
[https://dreamyguy.github.io/validate-color/][7]
|
|
35
|
-
|
|
36
|
-
On this page you can:
|
|
37
|
-
|
|
38
|
-
- **Validate HTML colors as you type**
|
|
39
|
-
|
|
40
|
-
_On my TODO list:_
|
|
41
|
-
|
|
42
|
-
- _See opaque colors against black and white backgrounds._
|
|
43
|
-
- _See colors with transparency in different contexts._
|
|
44
|
-
|
|
45
|
-
# Usage
|
|
46
|
-
|
|
47
|
-
**validate-color** is also [available as a package on `npm`][6] and can be installed as a depedency with:
|
|
48
|
-
|
|
49
|
-
npm i validate-color --save
|
|
50
|
-
|
|
51
|
-
As with any node module, first you'll have to import it with `require`:
|
|
52
|
-
|
|
53
|
-
```javascript
|
|
54
|
-
var validateColor = require("validate-color").default;
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
...or through `import`:
|
|
58
|
-
|
|
59
|
-
```javascript
|
|
60
|
-
import validateColor from "validate-color";
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
Once you've done the import, you'll be able to do checks like (example in **React**):
|
|
64
|
-
|
|
65
|
-
```javascript
|
|
66
|
-
import React from "react";
|
|
67
|
-
import validateColor from "validate-color";
|
|
68
|
-
|
|
69
|
-
const ColorBox = (props) => {
|
|
70
|
-
const { color = "", text = "" } = props;
|
|
71
|
-
const theColor = color && validateColor(color) ? color : "transparent";
|
|
72
|
-
return (
|
|
73
|
-
<div className="color-box" style={{ backgroundColor: theColor }}>
|
|
74
|
-
<p>{text}</p>
|
|
75
|
-
</div>
|
|
76
|
-
);
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
export default ColorBox;
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
> 👉 The source for a full-fledged color validation component can be [viewed here](https://github.com/dreamyguy/validate-color/blob/master/src/app/App.js). That component can be [seen in action here][7].
|
|
83
|
-
|
|
84
|
-
# Extend
|
|
85
|
-
|
|
86
|
-
One can "extend" the library by using only parts of it.
|
|
87
|
-
|
|
88
|
-
**1. Validate only HTML colors (`hex`, `rgb`, `rgba`, `hsl`, `hsla`, `hwb`, `lab`, `lch`), without `name`**
|
|
89
|
-
|
|
90
|
-
```javascript
|
|
91
|
-
import { validateHTMLColor } from "validate-color";
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
**2. Validate only `HEX` colors**
|
|
95
|
-
|
|
96
|
-
```javascript
|
|
97
|
-
import { validateHTMLColorHex } from "validate-color";
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
**3. Validate only `HSL` colors**
|
|
101
|
-
|
|
102
|
-
```javascript
|
|
103
|
-
import { validateHTMLColorHsl } from "validate-color";
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
**4. Validate only `NAME` colors**
|
|
107
|
-
|
|
108
|
-
```javascript
|
|
109
|
-
import { validateHTMLColorName } from "validate-color";
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
**5. Validate only `RGB` colors**
|
|
113
|
-
|
|
114
|
-
```javascript
|
|
115
|
-
import { validateHTMLColorRgb } from "validate-color";
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
**6. Validate only `SPECIAL NAME` colors**
|
|
119
|
-
|
|
120
|
-
```javascript
|
|
121
|
-
import { validateHTMLColorSpecialName } from "validate-color";
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
**7. Validate only `HWB` colors**
|
|
125
|
-
|
|
126
|
-
```javascript
|
|
127
|
-
import { validateHTMLColorHwb } from "validate-color";
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
**8. Validate only `LAB` colors**
|
|
131
|
-
|
|
132
|
-
```javascript
|
|
133
|
-
import { validateHTMLColorLab } from "validate-color";
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
**9. Validate only `LCH` colors**
|
|
137
|
-
|
|
138
|
-
```javascript
|
|
139
|
-
import { validateHTMLColorLch } from "validate-color";
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
> 👉 I was proactive and added validation to these relatively new HTML/CSS colors (**HWB** & **LAB** & **LCH**), but since [they're still drafts at the time of this writing][9], they might still be not fully supported at the time of this reading.
|
|
143
|
-
|
|
144
|
-
# Preventing ReDoS (`regex` denial-of-service) attacks
|
|
145
|
-
|
|
146
|
-
A ReDoS vulnerability [was reported as an issue](https://github.com/dreamyguy/validate-color/issues/28) on Oct 14, 2022, but that went under my radar. It was just today (Jan 29, 2023) I came across the issue, and luckily I had time to look into it.
|
|
147
|
-
|
|
148
|
-
This vulnerability was officially reported as **`CVE-2021-40892`**, and is listed a few places: [1](https://nvd.nist.gov/vuln/detail/CVE-2021-40892), [2](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-40892), [3](https://security.snyk.io/vuln/SNYK-JS-VALIDATECOLOR-2935878), [4](https://cve.report/CVE-2021-40892), [5](https://feedly.com/cve/CVE-2021-40892).
|
|
149
|
-
|
|
150
|
-
A similar problem was reported for the [`color-string` package](https://security.snyk.io/vuln/SNYK-JS-COLORSTRING-1082939), versions < 1.5.5.
|
|
151
|
-
|
|
152
|
-
A good article by Godson Obielum: [How to protect against regex denial-of-service (ReDoS) attacks](https://blog.logrocket.com/protect-against-regex-denial-of-service-redos-attacks/).
|
|
153
|
-
|
|
154
|
-
The issue is caused by the "greedy" character in `regex`, the infamous `+`. I've made amendments that limit the number of both spaces and digits by `5`, instead of having no limits.
|
|
155
|
-
|
|
156
|
-
I've also made patterns stricter and removed redundant optionals, simplifying whenever possible.
|
|
157
|
-
|
|
158
|
-
> 👉 All current `regex` have been tested with https://regex.rip/ and `npx redos-detector check "<regex pattern>" --maxSteps 10000)` (see [redos-detector](https://www.npmjs.com/package/redos-detector) for more options).
|
|
159
|
-
|
|
160
|
-
**That will, from this point onwards, invalidate otherwise valid colors that cross that threshold.**
|
|
161
|
-
|
|
162
|
-
Since this is an important update, I'm releasing it as a patch ([`v2.2.3`](https://github.com/dreamyguy/validate-color/releases/tag/v2.2.3))
|
|
163
|
-
|
|
164
|
-
# Development
|
|
165
|
-
|
|
166
|
-
## Getting started
|
|
167
|
-
|
|
168
|
-
Clone this repo locally. You'll need to have [NodeJS][1] installed. Install all dependencies by running:
|
|
169
|
-
|
|
170
|
-
npm i
|
|
171
|
-
|
|
172
|
-
## Run it locally
|
|
173
|
-
|
|
174
|
-
To start the app locally, run:
|
|
175
|
-
|
|
176
|
-
npm run start
|
|
177
|
-
|
|
178
|
-
This command fires up the application on port `9900`, making it visible on http://localhost:9900. Because this app is based on [create-react-app][2], the port number should be configured on the [.env](https://github.com/dreamyguy/validate-color/blob/master/.env#L1) file.
|
|
179
|
-
|
|
180
|
-
## Building the frontend for Production
|
|
181
|
-
|
|
182
|
-
When you're ready to build for production, run:
|
|
183
|
-
|
|
184
|
-
npm run build
|
|
185
|
-
|
|
186
|
-
This command compiles all production-optimised resources to a folder called **build**. It's meant to be run remotely, at the environment host, at build time.
|
|
187
|
-
|
|
188
|
-
## Building for NPM
|
|
189
|
-
|
|
190
|
-
When you're done with your changes, run:
|
|
191
|
-
|
|
192
|
-
npm run build-npm
|
|
193
|
-
|
|
194
|
-
This command compiles the distribution-optimised `javascript` to `lib/index.js`, a file compiled out of [src/validate-color/index.js][3].
|
|
195
|
-
|
|
196
|
-
> 👉 Note that the `lib/` folder and its contents are only available at the [NPM distribution][6].
|
|
197
|
-
|
|
198
|
-
# Testing
|
|
199
|
-
|
|
200
|
-
This project wouldn't be complete without proper testing.
|
|
201
|
-
|
|
202
|
-
[Jest][4] is my Unit Testing framework of choice. It's well documented and shares good practices & syntax with its most known predecessors (Mocha, Jasmine, etc). [Babel][5] was introduced as a dependency to the project because of Jest, but it was worth it since now we can use **ES6** syntax on our tests as well.
|
|
203
|
-
|
|
204
|
-
Run all tests, in watch mode:
|
|
205
|
-
|
|
206
|
-
npm run test
|
|
207
|
-
|
|
208
|
-
Tests are also run through [Travis][8] on every push to `master`. The build status is shown [at the top of this README](https://github.com/dreamyguy/validate-color#validate-color).
|
|
209
|
-
|
|
210
|
-
> 👉 All tests are named according to the file they're testing: `index.js` -> _`index.test.js`_, and reside under the same directory. Since `Jest` comes as courtesy of [CRA][2], all tests should be placed under the [src/](https://github.com/dreamyguy/validate-color/blob/master/src/) folder.
|
|
211
|
-
|
|
212
|
-
# Deploying
|
|
213
|
-
|
|
214
|
-
This repo is a hybrid one. It:
|
|
215
|
-
|
|
216
|
-
- Builds the NPM distribution
|
|
217
|
-
- Builds the GitHub Page that serves as a demo/showcase
|
|
218
|
-
|
|
219
|
-
There are 3 commands one can run to deploy to these two places.
|
|
220
|
-
|
|
221
|
-
**Deploy to GitHub Pages**
|
|
222
|
-
|
|
223
|
-
npm run deploy
|
|
224
|
-
|
|
225
|
-
**Deploy to NPM**
|
|
226
|
-
|
|
227
|
-
npm run deploy-npm
|
|
228
|
-
|
|
229
|
-
**Deploy to both places at once**
|
|
230
|
-
|
|
231
|
-
npm run release
|
|
232
|
-
|
|
233
|
-
> ⚠️ Make sure to bump version before releasing!
|
|
234
|
-
|
|
235
|
-
## Good to know
|
|
236
|
-
|
|
237
|
-
### License
|
|
238
|
-
|
|
239
|
-
[MIT](LICENSE)
|
|
240
|
-
|
|
241
|
-
### Credits & Resources
|
|
242
|
-
|
|
243
|
-
- [Source from which the color name list was extracted from](https://htmlcolorcodes.com/color-names/)
|
|
244
|
-
- [The Ultimate Guide to CSS Colors 2020 Edition](https://dev.to/alvaromontoro/the-ultimate-guide-to-css-colors-2020-edition-1bh1#hsl)
|
|
245
|
-
- [MDN: CSS Colors](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value)
|
|
246
|
-
- [MDN: Color Picker tool](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Colors/Color_picker_tool)
|
|
247
|
-
- [CSS Color Module Level 4 Editor's Draft][9]
|
|
248
|
-
- [Lea Verou: LCH colors in CSS: what, why, and how?][10]
|
|
249
|
-
- [LCH Colour Picker][11]
|
|
250
|
-
|
|
251
|
-
### About
|
|
252
|
-
|
|
253
|
-
**Validate Color** was put together by [Wallace Sidhrée][1]. 👨💻🇳🇴
|
|
254
|
-
|
|
255
|
-
[1]: http://sidhree.com/
|
|
256
|
-
[2]: https://facebook.github.io/create-react-app/
|
|
257
|
-
[3]: https://github.com/dreamyguy/validate-color/blob/master/src/validate-color/index.js
|
|
258
|
-
[4]: https://jestjs.io/
|
|
259
|
-
[5]: https://babeljs.io/
|
|
260
|
-
[6]: https://www.npmjs.com/package/validate-color
|
|
261
|
-
[7]: https://dreamyguy.github.io/validate-color/
|
|
262
|
-
[8]: https://travis-ci.com/dreamyguy/validate-color
|
|
263
|
-
[9]: https://drafts.csswg.org/css-color/
|
|
264
|
-
[10]: https://lea.verou.me/2020/04/lch-colors-in-css-what-why-and-how/
|
|
265
|
-
[11]: https://css.land/lch/
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
export function validateHTMLColor(input: string): boolean;
|
|
2
|
-
export function validateHTMLColorHex(input: string): boolean;
|
|
3
|
-
export function validateHTMLColorHsl(input: string): boolean;
|
|
4
|
-
export function validateHTMLColorName(input: string): boolean;
|
|
5
|
-
export function validateHTMLColorRgb(input: string): boolean;
|
|
6
|
-
export function validateHTMLColorSpecialName(input: string): boolean;
|
|
7
|
-
export function validateHTMLColorHwb(input: string): boolean;
|
|
8
|
-
export function validateHTMLColorLab(input: string): boolean;
|
|
9
|
-
export function validateHTMLColorLch(input: string): boolean;
|
|
10
|
-
export default function validateColor(input: string): boolean;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
module.exports=function(e){var r={};function t(n){if(r[n])return r[n].exports;var a=r[n]={i:n,l:!1,exports:{}};return e[n].call(a.exports,a,a.exports,t),a.l=!0,a.exports}return t.m=e,t.c=r,t.d=function(e,r,n){t.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:n})},t.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},t.t=function(e,r){if(1&r&&(e=t(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(t.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var a in e)t.d(n,a,function(r){return e[r]}.bind(null,a));return n},t.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(r,"a",r),r},t.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},t.p="",t(t.s=0)}([function(e,r,t){"use strict";t.r(r),t.d(r,"validateHTMLColorName",(function(){return l})),t.d(r,"validateHTMLColorSpecialName",(function(){return i})),t.d(r,"validateHTMLColorHex",(function(){return u})),t.d(r,"validateHTMLColorRgb",(function(){return g})),t.d(r,"validateHTMLColorHsl",(function(){return y})),t.d(r,"validateHTMLColorHwb",(function(){return L})),t.d(r,"validateHTMLColorLab",(function(){return S})),t.d(r,"validateHTMLColorLch",(function(){return m})),t.d(r,"validateHTMLColor",(function(){return G}));const n=e=>e&&"string"==typeof e,a=["AliceBlue","AntiqueWhite","Aqua","Aquamarine","Azure","Beige","Bisque","Black","BlanchedAlmond","Blue","BlueViolet","Brown","BurlyWood","CadetBlue","Chartreuse","Chocolate","Coral","CornflowerBlue","Cornsilk","Crimson","Cyan","DarkBlue","DarkCyan","DarkGoldenrod","DarkGray","DarkGrey","DarkGreen","DarkKhaki","DarkMagenta","DarkOliveGreen","DarkOrange","DarkOrchid","DarkRed","DarkSalmon","DarkSeaGreen","DarkSlateBlue","DarkSlateGray","DarkSlateGrey","DarkTurquoise","DarkViolet","DeepPink","DeepSkyBlue","DimGray","DimGrey","DodgerBlue","FireBrick","FloralWhite","ForestGreen","Fuchsia","Gainsboro","GhostWhite","Gold","Goldenrod","Gray","Grey","Green","GreenYellow","HoneyDew","HotPink","IndianRed","Indigo","Ivory","Khaki","Lavender","LavenderBlush","LawnGreen","LemonChiffon","LightBlue","LightCoral","LightCyan","LightGoldenrodYellow","LightGray","LightGrey","LightGreen","LightPink","LightSalmon","LightSalmon","LightSeaGreen","LightSkyBlue","LightSlateGray","LightSlateGrey","LightSteelBlue","LightYellow","Lime","LimeGreen","Linen","Magenta","Maroon","MediumAquamarine","MediumBlue","MediumOrchid","MediumPurple","MediumSeaGreen","MediumSlateBlue","MediumSlateBlue","MediumSpringGreen","MediumTurquoise","MediumVioletRed","MidnightBlue","MintCream","MistyRose","Moccasin","NavajoWhite","Navy","OldLace","Olive","OliveDrab","Orange","OrangeRed","Orchid","PaleGoldenrod","PaleGreen","PaleTurquoise","PaleVioletRed","PapayaWhip","PeachPuff","Peru","Pink","Plum","PowderBlue","Purple","RebeccaPurple","Red","RosyBrown","RoyalBlue","SaddleBrown","Salmon","SandyBrown","SeaGreen","SeaShell","Sienna","Silver","SkyBlue","SlateBlue","SlateGray","SlateGrey","Snow","SpringGreen","SteelBlue","Tan","Teal","Thistle","Tomato","Turquoise","Violet","Wheat","White","WhiteSmoke","Yellow","YellowGreen"],o=["currentColor","inherit","transparent"],l=e=>{let r=!1;return n(e)&&a.map(t=>(e.toLowerCase()===t.toLowerCase()&&(r=!0),null)),r},i=e=>{let r=!1;return n(e)&&o.map(t=>(e.toLowerCase()===t.toLowerCase()&&(r=!0),null)),r},u=e=>{if(n(e)){const r=/^#([\da-f]{3}){1,2}$|^#([\da-f]{4}){1,2}$/i;return e&&r.test(e)}return!1},d="(([\\d]{0,5})((\\.([\\d]{1,5}))?))",s=`(${d}%)`,c="(([0-9]|[1-9][0-9]|100)%)",f=`(${c}|(0?((\\.([\\d]{1,5}))?))|1)`,h=`([\\s]{0,5})\\)?)(([\\s]{0,5})(\\/?)([\\s]{1,5})${`(((${c}))|(0?((\\.([\\d]{1,5}))?))|1))?`}([\\s]{0,5})\\)`,$="(-?(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-9][0-9]|3[0-5][0-9])((\\.([\\d]{1,5}))?)|360)(deg)?)",g=e=>{if(n(e)){const r="([\\s]{0,5})([\\d]{1,5})%?([\\s]{0,5}),?",t="((([\\s]{0,5}),?([\\s]{0,5}))|(([\\s]{1,5})))",n=new RegExp(`^(rgb)a?\\(${`${r}${t}`}${`${r}${t}`}${`${r}${t}`}(${"(\\/?([\\s]{0,5})(0?\\.?([\\d]{1,5})%?([\\s]{0,5}))?|1|0)"})?\\)$`);return e&&n.test(e)}return!1},y=e=>{if(n(e)){const r=new RegExp(`^(hsl)a?\\((([\\s]{0,5})(${$}|${"(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-9][0-9]|3[0-9][0-9]|400)grad)"}|${"((([0-5])?\\.([\\d]{1,5})|6\\.([0-9]|1[0-9]|2[0-8])|[0-6])rad)"}|${"((0?((\\.([\\d]{1,5}))?)|1)turn)"})((([\\s]{0,5}),([\\s]{0,5}))|(([\\s]{1,5}))))(([\\s]{0,5})(0|${c})((([\\s]{0,5}),([\\s]{0,5}))|(([\\s]{1,5}))))(([\\s]{0,5})(0|${c})([\\s]{0,5})\\)?)(([\\s]{0,5})(\\/?|,?)([\\s]{0,5})(((${c}))|(0?((\\.([\\d]{1,5}))?))|1))?\\)$`);return e&&r.test(e)}return!1},L=e=>{if(n(e)){const r=new RegExp(`^(hwb\\(([\\s]{0,5})${$}([\\s]{1,5}))((0|${c})([\\s]{1,5}))((0|${c})${h}$`);return e&&r.test(e)}return!1},S=e=>{if(n(e)){const r="(-?(([0-9]|[1-9][0-9]|1[0-5][0-9])((\\.([\\d]{1,5}))?)?|160))",t=new RegExp(`^(lab\\(([\\s]{0,5})${s}([\\s]{1,5})${r}([\\s]{1,5})${r}${h}$`);return e&&t.test(e)}return!1},m=e=>{if(n(e)){const r="((([0-9]|[1-9][0-9])?((\\.([\\d]{1,5}))?)|100)(%)?)",t=""+d,n=`((${$})|(0|${f})|(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-9][0-9]|3[0-5][0-9])((\\.([\\d]{1,5}))?)|360))`,a=`(\\/([\\s]{0,5})${f})`,o=new RegExp(`^lch\\(${`(([\\s]{0,5})${r}([\\s]{1,5})${t}([\\s]{1,5})${n}([\\s]{0,5})(${a})?)`}\\)$`);return e&&o.test(e)}return!1},G=e=>!!(e&&u(e)||g(e)||y(e)||L(e)||S(e)||m(e));r.default=e=>!!(e&&u(e)||l(e)||i(e)||g(e)||y(e)||L(e)||S(e)||m(e))}]);
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "validate-color",
|
|
3
|
-
"version": "2.2.4",
|
|
4
|
-
"private": false,
|
|
5
|
-
"description": "Validate HTML colors by 'name', 'special name', 'hex', 'rgb', 'rgba', 'hsl', 'hsla', 'hwb', 'lab' or 'lch' values",
|
|
6
|
-
"keywords": [
|
|
7
|
-
"validation",
|
|
8
|
-
"color",
|
|
9
|
-
"colors",
|
|
10
|
-
"colour",
|
|
11
|
-
"colours",
|
|
12
|
-
"validate color",
|
|
13
|
-
"validate colour",
|
|
14
|
-
"color validation",
|
|
15
|
-
"colour validation",
|
|
16
|
-
"HTML color validation",
|
|
17
|
-
"HTML colour validation",
|
|
18
|
-
"validate HTML color",
|
|
19
|
-
"validate HTML colour",
|
|
20
|
-
"hex",
|
|
21
|
-
"rgb",
|
|
22
|
-
"rgba",
|
|
23
|
-
"hsl",
|
|
24
|
-
"hsla",
|
|
25
|
-
"hwb",
|
|
26
|
-
"lab",
|
|
27
|
-
"lch",
|
|
28
|
-
"css"
|
|
29
|
-
],
|
|
30
|
-
"homepage": "https://dreamyguy.github.io/validate-color/",
|
|
31
|
-
"repository": {
|
|
32
|
-
"type": "git",
|
|
33
|
-
"url": "https://github.com/dreamyguy/validate-color"
|
|
34
|
-
},
|
|
35
|
-
"main": "lib/index.js",
|
|
36
|
-
"types": "lib/index.d.ts",
|
|
37
|
-
"author": {
|
|
38
|
-
"name": "Wallace Sidhrée",
|
|
39
|
-
"email": "i@dreamyguy.com",
|
|
40
|
-
"url": "http://sidhree.com/"
|
|
41
|
-
},
|
|
42
|
-
"copyright": "Copyright (c) Wallace Sidhrée - All rights reserved.",
|
|
43
|
-
"license": "MIT",
|
|
44
|
-
"devDependencies": {
|
|
45
|
-
"@babel/core": "^7.15.8",
|
|
46
|
-
"@babel/preset-env": "^7.15.8",
|
|
47
|
-
"@babel/preset-react": "^7.14.5",
|
|
48
|
-
"babel-loader": "^8.2.3",
|
|
49
|
-
"fork-me-on-github": "^1.0.6",
|
|
50
|
-
"gh-pages": "^3.2.3",
|
|
51
|
-
"node-sass": "^6.0.1",
|
|
52
|
-
"react": "^17.0.2",
|
|
53
|
-
"react-dom": "^17.0.2",
|
|
54
|
-
"react-emojis": "^1.0.6",
|
|
55
|
-
"react-scripts": "^4.0.3",
|
|
56
|
-
"webpack": "4.44.2",
|
|
57
|
-
"webpack-cli": "^4.2.0"
|
|
58
|
-
},
|
|
59
|
-
"scripts": {
|
|
60
|
-
"start": "react-scripts start",
|
|
61
|
-
"prebuild": "echo 🚀 Runnin 'build', hang tight!",
|
|
62
|
-
"build": "react-scripts build",
|
|
63
|
-
"postbuild": "echo 🎉 'build' was completed",
|
|
64
|
-
"prebuild-npm": "./bin/preBuildNpm.sh",
|
|
65
|
-
"build-npm": "NODE_ENV=npm webpack --config webpack.config.npm.js",
|
|
66
|
-
"postbuild-npm": "./bin/postBuildNpm.sh",
|
|
67
|
-
"test": "react-scripts test",
|
|
68
|
-
"testTravis": "CI=true react-scripts test",
|
|
69
|
-
"eject": "react-scripts eject",
|
|
70
|
-
"predeploy": "npm run build",
|
|
71
|
-
"deploy": "gh-pages -d build",
|
|
72
|
-
"deploy-npm": "npm run build-npm && npm publish",
|
|
73
|
-
"release": "npm run deploy && npm run deploy-npm"
|
|
74
|
-
},
|
|
75
|
-
"eslintConfig": {
|
|
76
|
-
"extends": "react-app"
|
|
77
|
-
},
|
|
78
|
-
"browserslist": {
|
|
79
|
-
"production": [
|
|
80
|
-
">0.2%",
|
|
81
|
-
"not dead",
|
|
82
|
-
"not op_mini all"
|
|
83
|
-
],
|
|
84
|
-
"development": [
|
|
85
|
-
"last 1 chrome version",
|
|
86
|
-
"last 1 firefox version",
|
|
87
|
-
"last 1 safari version"
|
|
88
|
-
]
|
|
89
|
-
},
|
|
90
|
-
"dependencies": {}
|
|
91
|
-
}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
var validateColor = require('../lib/index');
|
|
2
|
-
|
|
3
|
-
function build_blank(n) {
|
|
4
|
-
// let ret = "rgb(0" // original
|
|
5
|
-
let ret = "rg"
|
|
6
|
-
for (let i = 0; i < n; i++) {
|
|
7
|
-
ret += " "
|
|
8
|
-
}
|
|
9
|
-
return ret + "!";
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
// 'rg !'
|
|
13
|
-
// 'rg !'
|
|
14
|
-
|
|
15
|
-
// * Simulating 'validateColor.validateHTMLColorRgb('rgb(0 0 0)')'
|
|
16
|
-
|
|
17
|
-
for(let i = 1; i <= 5000000; i++) {
|
|
18
|
-
const attackStr = build_blank(i)
|
|
19
|
-
if (i < 30) {
|
|
20
|
-
console.log('🚀 ~ file: redos.js:21 ~ attackStr', attackStr);
|
|
21
|
-
}
|
|
22
|
-
// if (i % 100 === 0) {
|
|
23
|
-
// const time = Date.now();
|
|
24
|
-
// const attackStr = build_blank(i)
|
|
25
|
-
// // validateColor.validateHTMLColorRgb(attackStr)
|
|
26
|
-
// const timeCost = Date.now() - time;
|
|
27
|
-
// console.log(`attackStr.length: ${attackStr.length}: ${timeCost} ms`)
|
|
28
|
-
// }
|
|
29
|
-
}
|