Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 2 additions & 12 deletions packages/input_schema/src/input_schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,7 @@ export function parseAjvError(
message = m('inputSchema.validation.generic', { rootName, fieldKey, message: error.message });
} else if (error.keyword === 'required') {
fieldKey = error.params.missingProperty;
if (fieldKey === 'allowRelative') {
// this is the case, when allowAbsolute is set to false, but allowRelative is not set
message = m('inputSchema.validation.datepickerNoType', { rootName });
} else {
message = m('inputSchema.validation.required', { rootName, fieldKey });
}
message = m('inputSchema.validation.required', { rootName, fieldKey });
} else if (error.keyword === 'additionalProperties') {
fieldKey = error.params.additionalProperty;
message = m('inputSchema.validation.additionalProperty', { rootName, fieldKey });
Expand All @@ -63,12 +58,7 @@ export function parseAjvError(
message = m('inputSchema.validation.generic', { rootName, fieldKey, message: errorMessage });
} else if (error.keyword === 'const') {
fieldKey = error.instancePath.split('/').pop()!;
// This is a special case for datepicker fields, where both allowAbsolute and allowRelative properties are set to false
if (fieldKey === 'allowRelative' || fieldKey === 'allowAbsolute') {
message = m('inputSchema.validation.datepickerNoType', { rootName });
} else {
message = m('inputSchema.validation.generic', { rootName, fieldKey, message: error.message });
}
message = m('inputSchema.validation.generic', { rootName, fieldKey, message: error.message });
} else {
fieldKey = error.instancePath.split('/').pop()!;
message = m('inputSchema.validation.generic', { rootName, fieldKey, message: error.message });
Expand Down
10 changes: 0 additions & 10 deletions packages/input_schema/src/intl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,6 @@ const intlStrings = {
'Field schema.properties.{fieldKey} does not exist, but it is specified in schema.required. Either define the field or remove it from schema.required.',
'inputSchema.validation.proxyGroupMustBeArrayOfStrings':
'Field {rootName}.{fieldKey}.apifyProxyGroups must be an array of strings.',
'inputSchema.validation.datepickerInvalidFormatAbsolute':
'Field {rootName}.{fieldKey} must be a string in format "YYYY-MM-DD".',
'inputSchema.validation.datepickerInvalidFormatRelative':
'Field {rootName}.{fieldKey} must be a string in format "+/- number unit". Supported units are "day", "week", "month" and "year".',
'inputSchema.validation.datepickerInvalidFormatBoth':
'Field {rootName}.{fieldKey} must be a string in format "YYYY-MM-DD" or "+/- number unit". Supported units are "day", "week", "month" and "year".',
'inputSchema.validation.datepickerInvalidDate':
'Field {rootName}.{fieldKey} must be a valid date.',
'inputSchema.validation.datepickerNoType':
'Field {rootName} must accept absolute, relative or both dates. Set "allowAbsolute", "allowRelative" or both properties.',
};

/**
Expand Down
20 changes: 5 additions & 15 deletions packages/input_schema/src/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -123,18 +123,8 @@
"editor": { "enum": ["datepicker"] },
"sectionCaption": { "type": "string" },
"sectionDescription": { "type": "string" },
"allowAbsolute": { "type": "boolean" },
"allowRelative": { "type": "boolean" }
},
"if": {
"required": ["allowAbsolute"],
"properties": { "allowAbsolute": { "const": false } }
},
"then": { "required": ["type", "title", "description", "editor", "allowRelative"] },
"anyOf": [
{ "properties": { "allowAbsolute": { "const": true } } },
{ "properties": { "allowRelative": { "const": true } } }
]
"dateType": { "enum": ["absolute", "relative", "absoluteOrRelative"] }
}
},
"else": {
"additionalProperties": false,
Expand All @@ -149,8 +139,8 @@
"nullable": { "type": "boolean" },
"minLength": { "type": "integer" },
"maxLength": { "type": "integer" },
"editor": { "enum": ["javascript", "python", "textfield", "textarea", "datepicker", "hidden"] },
"isSecret": { "type": "boolean" },
"editor": { "enum": ["javascript", "python", "textfield", "textarea", "hidden"] },
"isSecret": { "enum": [false] },
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is to force it to just a single value?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's already after the

"if": {
    properties": {
        "isSecret": {
            "not": {
                "const": true
             }
         }
    }
},

So there can't be any other boolean value then false. It's not necessary but I like it in the same way I did with:

"editor": { "enum": ["datepicker"] },

"sectionCaption": { "type": "string" },
"sectionDescription": { "type": "string" }
}
Expand All @@ -165,7 +155,7 @@
"example": { "type": "string" },
"nullable": { "type": "boolean" },
"editor": { "enum": ["textfield", "textarea", "hidden"] },
"isSecret": { "type": "boolean" },
"isSecret": { "enum": [true] },
"sectionCaption": { "type": "string" },
"sectionDescription": { "type": "string" }
}
Expand Down
6 changes: 2 additions & 4 deletions packages/input_schema/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,8 @@ export type StringFieldDefinition = CommonFieldDefinition<string> & {
enum?: readonly string[]; // required if editor is 'select'
enumTitles?: readonly string[]
isSecret?: boolean;
// Used for 'datepicker' editor, allowAbsolute is considered with default value true
// If only relative time is wanted, allowAbsolute must be explicitly set to false
allowAbsolute?: boolean;
allowRelative?: boolean;
// Used for 'datepicker' editor, absolute is considered as default value
dateType?: 'absolute' | 'relative' | 'absoluteOrRelative';
}

export type BooleanFieldDefinition = CommonFieldDefinition<boolean> & {
Expand Down
44 changes: 0 additions & 44 deletions packages/input_schema/src/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -248,50 +248,6 @@ export function validateInputUsingValidator(
}
}

// Check datepicker editor format
// TODO: enable validation for datepicker editor later
/* if (type === 'string' && editor === 'datepicker' && value && typeof value === 'string') {
const acceptAbsolute = allowAbsolute !== false;
const acceptRelative = allowRelative === true;
const isValidAbsolute = /^[0-9]{4}-[0-9]{2}-[0-9]{2}$/.test(value);
const isValidRelative = /^[+-] [0-9]+ (day|week|month|year)s?$/.test(value);
let isValidDate: boolean | undefined;

if (isValidAbsolute) {
const [year, month, day] = value.split('-').map(Number);
const date = new Date(`${year}-${month}-${day}`);

// Check if the date object is valid and matches the input string
isValidDate = date.getFullYear() === year
&& date.getMonth() + 1 === month
&& date.getDate() === day;
}

if (acceptAbsolute && !acceptRelative && !isValidAbsolute) {
fieldErrors.push(m('inputSchema.validation.datepickerInvalidFormatAbsolute', {
rootName: 'input',
fieldKey: property,
}));
} else if (acceptRelative && !acceptAbsolute && !isValidRelative) {
fieldErrors.push(m('inputSchema.validation.datepickerInvalidFormatRelative', {
rootName: 'input',
fieldKey: property,
}));
} else if ((acceptAbsolute && !acceptRelative && !isValidAbsolute)
|| (acceptRelative && !acceptAbsolute && !isValidRelative)
|| (acceptRelative && acceptAbsolute && !isValidAbsolute && !isValidRelative)) {
fieldErrors.push(m('inputSchema.validation.datepickerInvalidFormatBoth', {
rootName: 'input',
fieldKey: property,
}));
} else if (isValidDate === false && acceptAbsolute) {
fieldErrors.push(m('inputSchema.validation.datepickerInvalidDate', {
rootName: 'input',
fieldKey: property,
}));
}
} */

if (fieldErrors.length > 0) {
const message = fieldErrors.join(', ');
errors.push({ fieldKey: property, message });
Expand Down
2 changes: 1 addition & 1 deletion test/input_schema.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ describe('input_schema.json', () => {

expect(() => validateInputSchema(validator, schema)).toThrow(
'Input schema is not valid (Field schema.properties.myField.editor must be equal to one of the allowed values: '
+ '"javascript", "python", "textfield", "textarea", "datepicker", "hidden")',
+ '"javascript", "python", "textfield", "textarea", "hidden")',
);
});

Expand Down
149 changes: 15 additions & 134 deletions test/input_schema_definition.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { inputSchema, parseAjvError } from '@apify/input_schema';
import { inputSchema } from '@apify/input_schema';
import Ajv from 'ajv';

/**
Expand Down Expand Up @@ -301,7 +301,7 @@ describe('input_schema.json', () => {
});

describe('special cases for datepicker editor type', () => {
it('should accept allowAbsolute and allowRelative fields omitted', () => {
it('should accept dateType field omitted', () => {
expect(ajv.validate(inputSchema, {
title: 'Test input schema',
type: 'object',
Expand All @@ -317,96 +317,8 @@ describe('input_schema.json', () => {
})).toBe(true);
});

it('should accept allowAbsolute and allowRelative both set to true', () => {
expect(ajv.validate(inputSchema, {
title: 'Test input schema',
type: 'object',
schemaVersion: 1,
properties: {
myField: {
title: 'Field title',
description: 'My test field',
type: 'string',
editor: 'datepicker',
allowAbsolute: true,
allowRelative: true,
},
},
})).toBe(true);
});

it('should accept allowAbsolute=true and allowRelative=false', () => {
expect(ajv.validate(inputSchema, {
title: 'Test input schema',
type: 'object',
schemaVersion: 1,
properties: {
myField: {
title: 'Field title',
description: 'My test field',
type: 'string',
editor: 'datepicker',
allowAbsolute: true,
allowRelative: false,
},
},
})).toBe(true);
});

it('should accept allowAbsolute=false and allowRelative=true', () => {
expect(ajv.validate(inputSchema, {
title: 'Test input schema',
type: 'object',
schemaVersion: 1,
properties: {
myField: {
title: 'Field title',
description: 'My test field',
type: 'string',
editor: 'datepicker',
allowAbsolute: false,
allowRelative: true,
},
},
})).toBe(true);
});

it('should accept allowAbsolute=true', () => {
expect(ajv.validate(inputSchema, {
title: 'Test input schema',
type: 'object',
schemaVersion: 1,
properties: {
myField: {
title: 'Field title',
description: 'My test field',
type: 'string',
editor: 'datepicker',
allowAbsolute: true,
},
},
})).toBe(true);
});

it('should accept allowRelative=true', () => {
expect(ajv.validate(inputSchema, {
title: 'Test input schema',
type: 'object',
schemaVersion: 1,
properties: {
myField: {
title: 'Field title',
description: 'My test field',
type: 'string',
editor: 'datepicker',
allowRelative: true,
},
},
})).toBe(true);
});

it('should accept allowRelative=false', () => {
expect(ajv.validate(inputSchema, {
const isSchemaValid = (dateType: string) => {
return ajv.validate(inputSchema, {
title: 'Test input schema',
type: 'object',
schemaVersion: 1,
Expand All @@ -416,53 +328,22 @@ describe('input_schema.json', () => {
description: 'My test field',
type: 'string',
editor: 'datepicker',
allowRelative: false,
dateType,
},
},
})).toBe(true);
});
});
};

it('should not accept allowAbsolute=false', () => {
expect(ajv.validate(inputSchema, {
title: 'Test input schema',
type: 'object',
schemaVersion: 1,
properties: {
myField: {
title: 'Field title',
description: 'My test field',
type: 'string',
editor: 'datepicker',
allowAbsolute: false,
},
},
})).toBe(false);
expect(ajv.errorsText()).toContain('data/properties/myField must have required property \'allowRelative\'');
expect(parseAjvError(ajv.errors![0], 'schema.properties.myField')?.message)
.toEqual('Field schema.properties.myField must accept absolute, relative or both dates. '
+ 'Set "allowAbsolute", "allowRelative" or both properties.');
it('should accept valid dateType', () => {
['absolute', 'relative', 'absoluteOrRelative'].forEach((dateType) => {
expect(isSchemaValid(dateType)).toBe(true);
});
});

it('should not accept allowAbsolute=false allowRelative=false', () => {
expect(ajv.validate(inputSchema, {
title: 'Test input schema',
type: 'object',
schemaVersion: 1,
properties: {
myField: {
title: 'Field title',
description: 'My test field',
type: 'string',
editor: 'datepicker',
allowAbsolute: false,
allowRelative: false,
},
},
})).toBe(false);
expect(ajv.errorsText()).toContain('data/properties/myField/allowAbsolute must be equal to constant');
expect(parseAjvError(ajv.errors![0], 'schema.properties.myField')?.message)
.toEqual('Field schema.properties.myField must accept absolute, relative or both dates. '
+ 'Set "allowAbsolute", "allowRelative" or both properties.');
it('should not accept invalid dateType', () => {
['xxx', 'invalid'].forEach((dateType) => {
expect(isSchemaValid(dateType)).toBe(false);
});
});
});

Expand Down
Loading