From f412962dc8e84dd8c509dc41323f79b5c656adb7 Mon Sep 17 00:00:00 2001 From: Fredrik Nicol Date: Fri, 13 Apr 2018 15:38:45 +0200 Subject: [PATCH] WIP Add patcher to templorarily patch existing properties until they are solved by MDN --- package.json | 1 + src/data-types.ts | 24 +++++++--- src/data/css-patches.ts | 1 + src/patcher.ts | 104 ++++++++++++++++++++++++++++++++++++++++ src/properties.ts | 28 ++++------- yarn.lock | 2 +- 6 files changed, 135 insertions(+), 25 deletions(-) create mode 100644 src/data/css-patches.ts create mode 100644 src/patcher.ts diff --git a/package.json b/package.json index e1c9409..1ae4bbf 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "@types/jest": "^22.1.1", "@types/node": "^9.4.2", "@types/prettier": "^1.10.0", + "chalk": "^2.3.2", "chokidar": "^2.0.0", "flow-bin": "^0.69.0", "jest": "^22.2.1", diff --git a/src/data-types.ts b/src/data-types.ts index 090129e..486c8b2 100644 --- a/src/data-types.ts +++ b/src/data-types.ts @@ -1,16 +1,17 @@ +import * as properties from 'mdn-data/css/properties.json'; import * as syntaxes from 'mdn-data/css/syntaxes.json'; +import { compatPropertySyntax } from './compat'; import parse from './parser'; import typing, { addType, DataType, hasType, ResolvedType, Type, TypeType } from './typer'; -const MIN_TYPES = 3; - const dataTypes: { [key: string]: ResolvedType[] } = {}; export default dataTypes; export function resolveDataTypes( types: TypeType[], - resolver: (name: string) => ResolvedType[] = dataTypeResolver, + resolver: (name: string) => ResolvedType[] = simpleDataTypeResolver, + min = 3, ): ResolvedType[] { let resolvedDataTypes: ResolvedType[] = []; @@ -19,7 +20,7 @@ export function resolveDataTypes( case Type.DataType: { const resolvedDataType = resolver(type.name); - if (resolvedDataType.length >= MIN_TYPES) { + if (resolvedDataType.length >= min) { // Dissolve data type if it's too small resolvedDataTypes = addType(resolvedDataTypes, addDataType(type.name, resolvedDataType)); } else { @@ -46,12 +47,23 @@ export function resolveDataTypes( return resolvedDataTypes; } -function dataTypeResolver(name: string): ResolvedType[] { +function simpleDataTypeResolver(name: string): ResolvedType[] { return name in syntaxes - ? resolveDataTypes(typing(parse(syntaxes[name].syntax)), dataTypeResolver) + ? resolveDataTypes(typing(parse(syntaxes[name].syntax)), simpleDataTypeResolver) : [{ type: Type.String }]; } +export function createPropertyDataTypeResolver(propertyName: string, min?: number) { + const resolver: (dataTypeName: string) => ResolvedType[] = dataTypeName => { + const data = syntaxes[dataTypeName] || properties[dataTypeName]; + return data + ? resolveDataTypes(typing(compatPropertySyntax(propertyName, parse(data.syntax))), resolver, min) + : [{ type: Type.String }]; + }; + + return resolver; +} + function addDataType(name: string, types: ResolvedType[], index = 0): DataType { const realName = name + (index > 0 ? index + 1 : ''); diff --git a/src/data/css-patches.ts b/src/data/css-patches.ts new file mode 100644 index 0000000..fe57605 --- /dev/null +++ b/src/data/css-patches.ts @@ -0,0 +1 @@ +export const properties: { [property: string]: Pick } = {}; diff --git a/src/patcher.ts b/src/patcher.ts new file mode 100644 index 0000000..9d0f921 --- /dev/null +++ b/src/patcher.ts @@ -0,0 +1,104 @@ +import chalk from 'chalk'; +import { createPropertyDataTypeResolver, resolveDataTypes } from './data-types'; +import { properties as propertyPatches } from './data/css-patches'; +import parse from './parser'; +import typing, { addType, hasType, ResolvedType, Type } from './typer'; + +export default function patchProperty(name: string, types: ResolvedType[]): ResolvedType[] { + if (!(name in propertyPatches)) { + // Nothing to patch + return types; + } + + // Dissolve all data types to check whether it already exists or not + const dissolvedTypes = resolveDataTypes(types, createPropertyDataTypeResolver(name, Infinity), Infinity); + const patchTypes = typing(parse(propertyPatches[name].syntax)); + + let patchedTypes = types; + + for (const type of patchTypes) { + if (!hasType(dissolvedTypes, type)) { + patchedTypes = addType(patchedTypes, type); + + switch (type.type) { + case Type.DataType: + info('The property syntax patch with data type `<%s>` for property `%s` was added', type.name, name); + break; + case Type.Length: + info('The property syntax patch with `` for property `%s` was added', name); + break; + case Type.String: + info('The property syntax patch resolved to `string` for property `%s` was added', name); + break; + case Type.Number: + info('The property syntax patch resolved to `number` for property `%s` was added', name); + break; + case Type.NumericLiteral: + case Type.StringLiteral: + info('The property syntax patch with keyword `%s` for property `%s` was added', String(type.literal), name); + break; + default: + info('A property syntax patch for property `%s` was added', name); + } + } else { + switch (type.type) { + case Type.DataType: + error( + 'The property syntax patch with data type `<%s>` for property `%s` was ignored ' + + 'because it has been fixed permanently and must be removed', + type.name, + name, + ); + break; + case Type.Length: + error( + 'The property syntax patch with `` for property `%s` was ignored ' + + 'because it has been fixed permanently and must be removed', + name, + ); + break; + case Type.String: + error( + 'The property syntax patch resolved to `string` for property `%s` was ignored ' + + 'because it has been fixed permanently and must be removed', + name, + ); + break; + case Type.Number: + error( + 'The property syntax patch resolved to `number` for property `%s` was ignored ' + + 'because it has been fixed permanently and must be removed', + name, + ); + break; + case Type.NumericLiteral: + case Type.StringLiteral: + error( + 'The property syntax patch with keyword `%s` for property `%s` was ignored ' + + 'because it has been fixed permanently and must be removed', + String(type.literal), + name, + ); + break; + default: + error( + 'A property syntax patch for property `%s` was ignored because it has been fixed ' + + 'permanently and must be removed', + name, + ); + } + } + } + + return patchedTypes; +} + +const error: typeof console.error = (message, ...params) => { + // Complete the build process but exit with failure when done + process.exitCode = 1; + console.error(chalk.magenta('ERROR! ' + message), ...params); +}; + +const info: typeof console.info = (message, ...params) => { + console.info(chalk.cyan(message), ...params); +}; diff --git a/src/properties.ts b/src/properties.ts index 6807de9..40ae2bc 100644 --- a/src/properties.ts +++ b/src/properties.ts @@ -1,10 +1,10 @@ import * as properties from 'mdn-data/css/properties.json'; -import * as syntaxes from 'mdn-data/css/syntaxes.json'; import { compatPropertyNames, compatPropertySyntax, isDeprecated } from './compat'; -import { resolveDataTypes } from './data-types'; +import { createPropertyDataTypeResolver, resolveDataTypes } from './data-types'; import { properties as rawSvgProperties, syntaxes as svgSyntaxes } from './data/svg'; import parse from './parser'; -import typing, { ResolvedType, Type } from './typer'; +import patchProperty from './patcher'; +import typing, { ResolvedType } from './typer'; const IGNORES = [ // Custom properties @@ -44,9 +44,12 @@ for (const originalName in properties) { const property: IProperty = { name: originalName, - types: resolveDataTypes( - typing(compatPropertySyntax(originalName, parse(properties[originalName].syntax))), - createDataTypeResolver(originalName), + types: patchProperty( + originalName, + resolveDataTypes( + typing(compatPropertySyntax(originalName, parse(properties[originalName].syntax))), + createPropertyDataTypeResolver(originalName), + ), ), }; @@ -91,17 +94,6 @@ for (const name in rawSvgProperties) { } } -export function createDataTypeResolver(propertyName: string) { - const resolver: (dataTypeName: string) => ResolvedType[] = dataTypeName => { - const data = syntaxes[dataTypeName] || properties[dataTypeName]; - return data - ? resolveDataTypes(typing(compatPropertySyntax(propertyName, parse(data.syntax))), resolver) - : [{ type: Type.String }]; - }; - - return resolver; -} - export function isVendorProperty(name: string) { return REGEX_VENDOR_PROPERTY.test(name); } @@ -112,7 +104,7 @@ export function filterMissingProperties(propertyNames: string[]) { } function createSvgDataTypeResolver(propertyName: string) { - const resolver = createDataTypeResolver(propertyName); + const resolver = createPropertyDataTypeResolver(propertyName); const svgResolver: (dataTypeName: string) => ResolvedType[] = (dataTypeName: string) => dataTypeName in svgSyntaxes ? resolveDataTypes(typing(parse(svgSyntaxes[dataTypeName].syntax)), svgResolver) diff --git a/yarn.lock b/yarn.lock index 3969202..548e8a5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -521,7 +521,7 @@ chalk@^1.1.3: strip-ansi "^3.0.0" supports-color "^2.0.0" -chalk@^2.0.0, chalk@^2.0.1, chalk@^2.3.0: +chalk@^2.0.0, chalk@^2.0.1, chalk@^2.3.0, chalk@^2.3.2: version "2.3.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.2.tgz#250dc96b07491bfd601e648d66ddf5f60c7a5c65" dependencies: