diff --git a/bin/api-docs/gen-theme-reference.js b/bin/api-docs/gen-theme-reference.mjs similarity index 82% rename from bin/api-docs/gen-theme-reference.js rename to bin/api-docs/gen-theme-reference.mjs index 07a8c2fcc697d..051f23c3ea997 100644 --- a/bin/api-docs/gen-theme-reference.js +++ b/bin/api-docs/gen-theme-reference.mjs @@ -7,8 +7,13 @@ /** * External dependencies */ -const path = require( 'path' ); -const fs = require( 'fs' ); +import path from 'path'; +import fs from 'fs'; +import url from 'url'; +import $RefParser from '@apidevtools/json-schema-ref-parser'; + +const __dirname = path.dirname( url.fileURLToPath( import.meta.url ) ); + /** * Path to root project directory. * @@ -58,7 +63,7 @@ const END_TOKEN = ''; */ const TOKEN_PATTERN = new RegExp( START_TOKEN + '[^]*' + END_TOKEN ); -const themejson = require( THEME_JSON_SCHEMA_FILE ); +const themejson = await $RefParser.dereference( THEME_JSON_SCHEMA_FILE ); /** * Convert object keys to an array. @@ -74,42 +79,6 @@ const keys = ( maybeObject ) => { return Object.keys( maybeObject ); }; -/** - * Get definition from ref. - * - * @param {string} ref - * @return {Object} definition - * @throws {Error} If the referenced definition is not found in 'themejson.definitions'. - * - * @example - * getDefinition( '#/definitions/typographyProperties/properties/fontFamily' ) - * // returns themejson.definitions.typographyProperties.properties.fontFamily - */ -const resolveDefinitionRef = ( ref ) => { - const refParts = ref.split( '/' ); - const definition = refParts[ refParts.length - 1 ]; - if ( ! themejson.definitions[ definition ] ) { - throw new Error( `Can't resolve '${ ref }'. Definition not found` ); - } - return themejson.definitions[ definition ]; -}; - -/** - * Get properties from an array. - * - * @param {Object} items - * @return {Object} properties - */ -const getPropertiesFromArray = ( items ) => { - // if its a $ref resolve it - if ( items.$ref ) { - return resolveDefinitionRef( items.$ref ).properties; - } - - // otherwise just return the properties - return items.properties; -}; - /** * Convert settings properties to markup. * @@ -133,9 +102,7 @@ const getSettingsPropertiesMarkup = ( struct ) => { let type = props[ key ].type || ''; let ps = props[ key ].type === 'array' - ? keys( getPropertiesFromArray( props[ key ].items ) ) - .sort() - .join( ', ' ) + ? keys( props[ key ].items.properties ).sort().join( ', ' ) : ''; /* @@ -154,9 +121,7 @@ const getSettingsPropertiesMarkup = ( struct ) => { .map( ( item ) => item?.type === 'object' && item?.properties ? '_{' + - keys( getPropertiesFromArray( item ) ) - .sort() - .join( ', ' ) + + keys( item.properties ).sort().join( ', ' ) + '}_' : '' ) @@ -244,10 +209,6 @@ const formatType = ( prop ) => { if ( item.type ) { types.push( item.type ); } - // refComplete is always an object - if ( item.$ref && item.$ref === '#/definitions/refComplete' ) { - types.push( 'object' ); - } } ); type = [ ...new Set( types ) ].join( ', ' ); diff --git a/package-lock.json b/package-lock.json index 1cc4fb4bd8647..537b83feff974 100644 --- a/package-lock.json +++ b/package-lock.json @@ -85,6 +85,7 @@ "devDependencies": { "@actions/core": "1.9.1", "@actions/github": "5.0.0", + "@apidevtools/json-schema-ref-parser": "11.6.4", "@ariakit/test": "^0.3.7", "@babel/core": "7.24.3", "@babel/plugin-proposal-export-namespace-from": "7.18.9", @@ -325,6 +326,47 @@ "node": ">=6.0.0" } }, + "node_modules/@apidevtools/json-schema-ref-parser": { + "version": "11.6.4", + "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-11.6.4.tgz", + "integrity": "sha512-9K6xOqeevacvweLGik6LnZCb1fBtCOSIWQs8d096XGeqoLKC33UVMGz9+77Gw44KvbH4pKcQPWo4ZpxkXYj05w==", + "dev": true, + "dependencies": { + "@jsdevtools/ono": "^7.1.3", + "@types/json-schema": "^7.0.15", + "js-yaml": "^4.1.0" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/philsturgeon" + } + }, + "node_modules/@apidevtools/json-schema-ref-parser/node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, + "node_modules/@apidevtools/json-schema-ref-parser/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/@apidevtools/json-schema-ref-parser/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "node_modules/@appium/base-driver": { "version": "9.4.0", "resolved": "https://registry.npmjs.org/@appium/base-driver/-/base-driver-9.4.0.tgz", @@ -5597,6 +5639,12 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@jsdevtools/ono": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz", + "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==", + "dev": true + }, "node_modules/@juggle/resize-observer": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/@juggle/resize-observer/-/resize-observer-3.4.0.tgz", @@ -56248,6 +56296,40 @@ "@jridgewell/trace-mapping": "^0.3.9" } }, + "@apidevtools/json-schema-ref-parser": { + "version": "11.6.4", + "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-11.6.4.tgz", + "integrity": "sha512-9K6xOqeevacvweLGik6LnZCb1fBtCOSIWQs8d096XGeqoLKC33UVMGz9+77Gw44KvbH4pKcQPWo4ZpxkXYj05w==", + "dev": true, + "requires": { + "@jsdevtools/ono": "^7.1.3", + "@types/json-schema": "^7.0.15", + "js-yaml": "^4.1.0" + }, + "dependencies": { + "@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + } + } + }, "@appium/base-driver": { "version": "9.4.0", "resolved": "https://registry.npmjs.org/@appium/base-driver/-/base-driver-9.4.0.tgz", @@ -59958,6 +60040,12 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "@jsdevtools/ono": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz", + "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==", + "dev": true + }, "@juggle/resize-observer": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/@juggle/resize-observer/-/resize-observer-3.4.0.tgz", diff --git a/package.json b/package.json index 2ed3f7c108354..ffc65ba844adc 100644 --- a/package.json +++ b/package.json @@ -97,6 +97,7 @@ "devDependencies": { "@actions/core": "1.9.1", "@actions/github": "5.0.0", + "@apidevtools/json-schema-ref-parser": "11.6.4", "@ariakit/test": "^0.3.7", "@babel/core": "7.24.3", "@babel/plugin-proposal-export-namespace-from": "7.18.9", @@ -282,7 +283,7 @@ "docs:blocks": "node ./bin/api-docs/gen-block-lib-list.js", "docs:build": "npm-run-all docs:gen docs:blocks docs:api-ref docs:theme-ref", "docs:gen": "node ./docs/tool/index.js", - "docs:theme-ref": "node ./bin/api-docs/gen-theme-reference.js", + "docs:theme-ref": "node ./bin/api-docs/gen-theme-reference.mjs", "env": "wp-env", "fixtures:clean": "rimraf \"test/integration/fixtures/blocks/*.+(json|serialized.html)\"", "fixtures:generate": "cross-env GENERATE_MISSING_FIXTURES=y npm run test:unit test/integration/full-content/ && npm run format test/integration/fixtures/blocks/*.json", diff --git a/schemas/json/theme.json b/schemas/json/theme.json index f1666253e3de3..62a4f790c05f1 100644 --- a/schemas/json/theme.json +++ b/schemas/json/theme.json @@ -14,7 +14,8 @@ "description": "A reference to another property value. e.g. `styles.color.text`", "type": "string" } - } + }, + "additionalProperties": false }, "settingsPropertiesAppearanceTools": { "type": "object", @@ -792,7 +793,6 @@ "type": "object", "properties": { "custom": { - "description": "Generate custom CSS custom properties of the form `--wp--custom--{key}--{nested-key}: {value};`. `camelCased` keys are transformed to `kebab-case` as to follow the CSS property naming schema. Keys at different depth levels are separated by `--`, so keys should not include `--` in the name.", "$ref": "#/definitions/settingsCustomAdditionalProperties" } } @@ -839,6 +839,7 @@ ] }, "settingsBlocksPropertiesComplete": { + "description": "Settings defined on a per-block basis.", "type": "object", "properties": { "core/archives": { @@ -1144,6 +1145,7 @@ "additionalProperties": false }, "settingsCustomAdditionalProperties": { + "description": "Generate custom CSS custom properties of the form `--wp--custom--{key}--{nested-key}: {value};`. `camelCased` keys are transformed to `kebab-case` as to follow the CSS property naming schema. Keys at different depth levels are separated by `--`, so keys should not include `--` in the name.", "type": "object", "additionalProperties": { "oneOf": [ @@ -1892,6 +1894,7 @@ ] }, "stylesElementsPropertiesComplete": { + "description": "Styles defined on a per-element basis using the element's selector.", "type": "object", "properties": { "button": { @@ -1905,6 +1908,7 @@ "border": {}, "background": {}, "color": {}, + "dimensions": {}, "filter": {}, "shadow": {}, "outline": {}, @@ -1942,10 +1946,16 @@ }, { "properties": { + "background": {}, "border": {}, "color": {}, + "dimensions": {}, "spacing": {}, "typography": {}, + "filter": {}, + "shadow": {}, + "outline": {}, + "css": {}, ":hover": { "$ref": "#/definitions/stylesPropertiesComplete" }, @@ -2000,6 +2010,7 @@ "additionalProperties": false }, "stylesBlocksPropertiesComplete": { + "description": "Styles defined on a per-block basis using the block's selector.", "type": "object", "properties": { "core/archives": { @@ -2349,6 +2360,7 @@ }, { "properties": { + "background": {}, "border": {}, "color": {}, "dimensions": {}, @@ -2385,6 +2397,7 @@ }, { "properties": { + "background": {}, "border": {}, "color": {}, "dimensions": {}, @@ -2718,6 +2731,7 @@ }, { "properties": { + "background": {}, "border": {}, "color": {}, "dimensions": {}, @@ -2791,7 +2805,6 @@ "dimensions": {}, "custom": {}, "blocks": { - "description": "Settings defined on a per-block basis.", "$ref": "#/definitions/settingsBlocksPropertiesComplete" } }, @@ -2811,6 +2824,7 @@ "background": {}, "border": {}, "color": {}, + "dimensions": {}, "spacing": {}, "typography": {}, "filter": {}, @@ -2818,11 +2832,9 @@ "outline": {}, "css": {}, "elements": { - "description": "Styles defined on a per-element basis using the element's selector.", "$ref": "#/definitions/stylesElementsPropertiesComplete" }, "blocks": { - "description": "Styles defined on a per-block basis using the block's selector.", "$ref": "#/definitions/stylesBlocksPropertiesComplete" }, "variations": { diff --git a/schemas/json/wp-env.json b/schemas/json/wp-env.json index b559cb9d8a502..b082c861e4b67 100644 --- a/schemas/json/wp-env.json +++ b/schemas/json/wp-env.json @@ -82,8 +82,21 @@ "patternProperties": { "[a-zA-Z]": { "type": "object", - "$ref": "#/definitions/wpEnvProperties", - "additionalProperties": false + "allOf": [ + { "$ref": "#/definitions/wpEnvProperties" }, + { + "properties": { + "core": {}, + "phpVersion": {}, + "plugins": {}, + "themes": {}, + "port": {}, + "config": {}, + "mappings": {} + }, + "additionalProperties": false + } + ] } } }