├── .gitignore ├── .editorconfig ├── .eslintrc.json ├── descriptions ├── css │ └── properties │ │ ├── initial-letter.json │ │ ├── border-top-left-radius.json │ │ ├── quotes.json │ │ ├── border-top-right-radius.json │ │ ├── font-size.json │ │ ├── opacity.json │ │ ├── border-bottom-left-radius.json │ │ ├── border-bottom-right-radius.json │ │ ├── columns.json │ │ ├── caret-color.json │ │ ├── background-clip.json │ │ ├── background-color.json │ │ ├── border-top-width.json │ │ ├── box-sizing.json │ │ ├── font-family.json │ │ ├── letter-spacing.json │ │ ├── word-spacing.json │ │ ├── background-image.json │ │ ├── border-left-width.json │ │ ├── border-top-color.json │ │ ├── vertical-align.json │ │ ├── animation-play-state.json │ │ ├── border-bottom-width.json │ │ ├── border-left-color.json │ │ ├── border-right-width.json │ │ ├── cursor.json │ │ ├── flex.json │ │ ├── border-bottom-color.json │ │ ├── animation-duration.json │ │ ├── justify-self.json │ │ ├── line-height.json │ │ ├── border.json │ │ ├── box-shadow.json │ │ ├── animation-fill-mode.json │ │ ├── animation-timing-function.json │ │ ├── list-style-type.json │ │ ├── animation-direction.json │ │ ├── background-origin.json │ │ ├── animation-iteration-count.json │ │ ├── animation.json │ │ ├── border-color.json │ │ ├── border-width.json │ │ ├── break-after.json │ │ ├── border-image-width.json │ │ ├── break-before.json │ │ ├── break-inside.json │ │ ├── align-items.json │ │ ├── background-blend-mode.json │ │ ├── border-image.json │ │ ├── padding-right.json │ │ ├── border-left-style.json │ │ ├── border-right-style.json │ │ ├── border-style.json │ │ ├── text-overflow.json │ │ ├── z-index.json │ │ ├── animation-delay.json │ │ ├── border-bottom-style.json │ │ ├── text-decoration.json │ │ ├── background-repeat.json │ │ ├── background-size.json │ │ ├── border-image-source.json │ │ ├── border-radius.json │ │ ├── bottom.json │ │ ├── border-collapse.json │ │ ├── border-top.json │ │ ├── border-image-outset.json │ │ ├── border-left.json │ │ ├── background.json │ │ ├── border-right.json │ │ ├── font-weight.json │ │ ├── border-bottom.json │ │ ├── pointer-events.json │ │ ├── transform.json │ │ ├── background-attachment.json │ │ ├── animation-name.json │ │ ├── background-position.json │ │ ├── margin-top.json │ │ ├── background-position-y.json │ │ ├── overflow.json │ │ ├── background-position-x.json │ │ ├── border-spacing.json │ │ ├── align-content.json │ │ ├── caption-side.json │ │ ├── border-image-repeat.json │ │ ├── all.json │ │ ├── border-image-slice.json │ │ ├── border-right-color.json │ │ ├── display.json │ │ ├── align-self.json │ │ └── position.json └── LICENSE.md ├── .travis.yml ├── test ├── test.js ├── test-built-package.sh ├── json-format-rules.js ├── lint-wiki.js ├── lint-json.js └── content-rules.js ├── CODE_OF_CONDUCT.md ├── index.js ├── README.md ├── package.json ├── publishing-the-package.md ├── writing-short-descriptions.md ├── scripts └── scrape.js ├── LICENSE.txt └── project-overview.md /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules/ 2 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "airbnb-base", 3 | "root": true, 4 | "rules": { 5 | "no-console": "off", 6 | "import/no-extraneous-dependencies": ["error", {"devDependencies": ["./test/*.js", "./scripts/*.js"]}] 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /descriptions/css/properties/initial-letter.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "initial-letter": { 5 | "__short_description": "The initial-letter CSS property sets styling for dropped, raised, and sunken initial letters." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/border-top-left-radius.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "border-top-left-radius": { 5 | "__short_description": "The border-top-left-radius CSS property rounds the top-left corner of an element." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/quotes.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "quotes": { 5 | "__short_description": "The quotes CSS property sets how quotation marks appear." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/border-top-right-radius.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "border-top-right-radius": { 5 | "__short_description": "The border-top-right-radius CSS property rounds the top-right corner of an element." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/font-size.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "font-size": { 5 | "__short_description": "The font-size CSS property sets the size of the font." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/opacity.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "opacity": { 5 | "__short_description": "The opacity CSS property sets the transparency of an element or the degree to which content behind an element is visible." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/border-bottom-left-radius.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "border-bottom-left-radius": { 5 | "__short_description": "The border-bottom-left-radius CSS property rounds the bottom-left corner of an element." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: stable 3 | sudo: false 4 | notifications: 5 | email: false 6 | script: 7 | - npm test 8 | - bash test/test-built-package.sh 9 | deploy: 10 | provider: npm 11 | email: mdn-npm@mozilla.com 12 | api_key: $NPM_TOKEN 13 | on: 14 | tags: true 15 | repo: mdn/short-descriptions 16 | -------------------------------------------------------------------------------- /descriptions/css/properties/border-bottom-right-radius.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "border-bottom-right-radius": { 5 | "__short_description": "The border-bottom-right-radius CSS property rounds the bottom-right corner of an element." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/columns.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "columns": { 5 | "__short_description": "The columns CSS property sets the column width and column count of an element." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/caret-color.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "caret-color": { 5 | "__short_description": "The caret-color CSS property sets the color of the insertion caret, the visible marker where the next character typed will be inserted." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/background-clip.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "background-clip": { 5 | "__short_description": "The background-clip CSS property sets whether an element's background extends underneath its border box, padding box, or content box." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/background-color.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "background-color": { 5 | "__short_description": "The background-color CSS property sets the background color of an element." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/border-top-width.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "border-top-width": { 5 | "__short_description": "The border-top-width CSS property sets the width of the top border of an element." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/box-sizing.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "box-sizing": { 5 | "__short_description": "The box-sizing CSS property sets how the total width and height of an element is calculated." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/font-family.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "font-family": { 5 | "__short_description": "The font-family CSS property specifies a prioritized list of one or more font family names and/or generic family names for the selected element." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/letter-spacing.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "letter-spacing": { 5 | "__short_description": "The letter-spacing CSS property sets the spacing behavior between text characters." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/word-spacing.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "word-spacing": { 5 | "__short_description": "The word-spacing CSS property sets the length of space between words and between tags." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/background-image.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "background-image": { 5 | "__short_description": "The background-image CSS property sets one or more background images on an element." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/border-left-width.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "border-left-width": { 5 | "__short_description": "The border-left-width CSS property sets the width of the left border of an element." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/border-top-color.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "border-top-color": { 5 | "__short_description": "The border-top-color CSS property sets the color of an element's top border." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/vertical-align.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "vertical-align": { 5 | "__short_description": "The vertical-align CSS property sets vertical alignment of an inline or table-cell box." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/animation-play-state.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "animation-play-state": { 5 | "__short_description": "The animation-play-state CSS property sets whether an animation is running or paused." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/border-bottom-width.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "border-bottom-width": { 5 | "__short_description": "The border-bottom-width CSS property sets the width of the bottom border of a box." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/border-left-color.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "border-left-color": { 5 | "__short_description": "The border-left-color CSS property sets the color of an element's left border." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/border-right-width.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "border-right-width": { 5 | "__short_description": "The border-right-width CSS property sets the width of the right border of an element." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/cursor.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "cursor": { 5 | "__short_description": "The cursor CSS property sets the type of cursor, if any, to show when the mouse pointer is over an element." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/flex.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "flex": { 5 | "__short_description": "The flex CSS property sets how a flex item will grow or shrink to fit the space available in its flex container." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/border-bottom-color.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "border-bottom-color": { 5 | "__short_description": "The border-bottom-color CSS property sets the color of an element's bottom border." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-underscore-dangle */ 2 | const assert = require('assert'); 3 | 4 | const descriptions = require('..'); 5 | 6 | // Make sure the data is importable and does something vaguely useful 7 | assert(typeof descriptions.css.properties.opacity.__short_description === 'string'); 8 | assert(descriptions.css.properties.opacity.__short_description.length > 0); 9 | -------------------------------------------------------------------------------- /descriptions/css/properties/animation-duration.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "animation-duration": { 5 | "__short_description": "The animation-duration CSS property sets the length of time that an animation takes to complete one cycle." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/justify-self.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "justify-self": { 5 | "__short_description": "The CSS justify-self property set the way a box is justified inside its alignment container along the appropriate axis." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/line-height.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "line-height": { 5 | "__short_description": "The line-height CSS property sets the height of a line box. It's commonly used to set the distance between lines of text." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/border.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "border": { 5 | "__short_description": "The border shorthand CSS property sets an element's border." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/box-shadow.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "box-shadow": { 5 | "__short_description": "The box-shadow CSS property adds shadow effects around an element's frame. You can set multiple effects separated by commas." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/animation-fill-mode.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "animation-fill-mode": { 5 | "__short_description": "The animation-fill-mode CSS property sets how a CSS animation applies styles to its target before and after its execution." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/animation-timing-function.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "animation-timing-function": { 5 | "__short_description": "The animation-timing-function CSS property sets how an animation progresses through the duration of each cycle." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/list-style-type.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "list-style-type": { 5 | "__short_description": "The list-style-type CSS property sets the marker (such as a disc, character, or custom counter style) of a list item element." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/animation-direction.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "animation-direction": { 5 | "__short_description": "The animation-direction CSS property sets whether an animation should play forwards, backwards, or alternating back and forth." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/background-origin.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "background-origin": { 5 | "__short_description": "The background-origin CSS property sets the background's origin: from the border start, inside the border, or inside the padding." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/animation-iteration-count.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "animation-iteration-count": { 5 | "__short_description": "The animation-iteration-count CSS property sets the number of times an animation cycle should be played before stopping." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/animation.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "animation": { 5 | "__short_description": "The animation shorthand CSS property applies an animation between styles." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/border-color.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "border-color": { 5 | "__short_description": "The border-color shorthand CSS property sets the color of an element's border." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/border-width.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "border-width": { 5 | "__short_description": "The border-width shorthand CSS property sets the width of an element's border." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/break-after.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "break-after": { 5 | "__short_description": "The break-after CSS property sets how page, column, or region breaks should behave after a generated box. If there is no generated box, the property is ignored." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/border-image-width.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "border-image-width": { 5 | "__short_description": "The border-image-width CSS property sets the width of an element's border image." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/break-before.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "break-before": { 5 | "__short_description": "The break-before CSS property sets how page, column, or region breaks should behave before a generated box. If there is no generated box, the property is ignored." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/break-inside.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "break-inside": { 5 | "__short_description": "The break-inside CSS property sets how page, column, or region breaks should behave inside a generated box. If there is no generated box, the property is ignored." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/align-items.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "align-items": { 5 | "__short_description": "The CSS align-items property sets the align-self value on all direct children as a group." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/background-blend-mode.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "background-blend-mode": { 5 | "__short_description": "The background-blend-mode CSS property sets how an element's background images should blend with each other and with the element's background color." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/border-image.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "border-image": { 5 | "__short_description": "The border-image CSS property draws an image in place of an element's border-style." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/padding-right.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "padding-right": { 5 | "__short_description": "The padding-right CSS property sets the width of the padding area on the right side of an element." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/border-left-style.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "border-left-style": { 5 | "__short_description": "The border-left-style CSS property sets the line style of an element's left border." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/border-right-style.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "border-right-style": { 5 | "__short_description": "The border-right-style CSS property sets the line style of an element's right border." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/border-style.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "border-style": { 5 | "__short_description": "The border-style shorthand CSS property sets the line style for all four sides of an element's border." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/text-overflow.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "text-overflow": { 5 | "__short_description": "The text-overflow CSS property sets how hidden overflow content is signaled to users. It can be clipped, display an ellipsis (''), or display a custom string." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/z-index.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "z-index": { 5 | "__short_description": "The z-index CSS property sets the z-order of a positioned element and its descendants or flex items. Overlapping elements with a larger z-index cover those with a smaller one." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/animation-delay.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "animation-delay": { 5 | "__short_description": "The animation-delay CSS property sets when an animation starts. The animation can start later, immediately from its beginning, or immediately and partway through the animation." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/border-bottom-style.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "border-bottom-style": { 5 | "__short_description": "The border-bottom-style CSS property sets the line style of an element's bottom border." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/text-decoration.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "text-decoration": { 5 | "__short_description": "The text-decoration shorthand CSS property sets the appearance of decorative lines on text." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/LICENSE.md: -------------------------------------------------------------------------------- 1 | Prose from MDN, found in this directory, is by Mozilla Contributors and is 2 | licensed under [CC-BY-SA 2.5](http://creativecommons.org/licenses/by-sa/2.5/). 3 | You are free to modify and share that content, if you attribute the work and 4 | distribute it under the same terms. Visit [About 5 | MDN](https://developer.mozilla.org/en-US/docs/MDN/About#Using_MDN_Web_Docs_content) 6 | to learn more about MDN content, its authorship, and reuse. 7 | -------------------------------------------------------------------------------- /descriptions/css/properties/background-repeat.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "background-repeat": { 5 | "__short_description": "The background-repeat CSS property sets how background images are repeated. A background image can be repeated along the horizontal and vertical axes, or not repeated at all." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/background-size.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "background-size": { 5 | "__short_description": "The background-size CSS property sets the size of the element's background image. The image can be left to its natural size, stretched, or constrained to fit the available space." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/border-image-source.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "border-image-source": { 5 | "__short_description": "The border-image-source CSS property sets the source image used to create an element's border image." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/border-radius.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "border-radius": { 5 | "__short_description": "The border-radius CSS property rounds the corners of an element's outer border edge. You can set a single radius to make circular corners, or two radii to make elliptical corners." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/bottom.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "bottom": { 5 | "__short_description": "The bottom CSS property participates in setting the vertical position of a positioned element. It has no effect on non-positioned elements." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/border-collapse.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "border-collapse": { 5 | "__short_description": "The border-collapse CSS property sets whether cells inside a <table> have shared or separate borders." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/border-top.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "border-top": { 5 | "__short_description": "The border-top shorthand CSS property set an element's top border." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/border-image-outset.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "border-image-outset": { 5 | "__short_description": "The border-image-outset CSS property sets the distance by which an element's border image is set out from its border box." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/border-left.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "border-left": { 5 | "__short_description": "The border-left shorthand CSS property set an element's left border." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/background.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "background": { 5 | "__short_description": "The background shorthand CSS property sets all background style properties at once, such as color, image, origin and size, or repeat method." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/border-right.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "border-right": { 5 | "__short_description": "The border-right shorthand CSS property sets an element's right border." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/font-weight.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "font-weight": { 5 | "__short_description": "The font-weight CSS property sets the weight (or boldness) of the font. The weights available depend on the font-family you are using." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/border-bottom.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "border-bottom": { 5 | "__short_description": "The border-bottom shorthand CSS property sets an element's bottom border." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/pointer-events.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "pointer-events": { 5 | "__short_description": "The pointer-events CSS property sets under what circumstances (if any) a particular graphic element can become the target of pointer events." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/transform.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "transform": { 5 | "__short_description": "The transform CSS property lets you rotate, scale, skew, or translate an element. It modifies the coordinate space of the CSS visual formatting model." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/background-attachment.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "background-attachment": { 5 | "__short_description": "The background-attachment CSS property sets whether a background image's position is fixed within the viewport, or scrolls with its containing block." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Community Participation Guidelines 2 | 3 | This repository is governed by Mozilla's code of conduct and etiquette guidelines. 4 | For more details, please read the 5 | [Mozilla Community Participation Guidelines](https://www.mozilla.org/about/governance/policies/participation/). 6 | 7 | ## How to Report 8 | For more information on how to report violations of the Community Participation Guidelines, please read our [How to Report](https://www.mozilla.org/about/governance/policies/participation/reporting/) page. 9 | -------------------------------------------------------------------------------- /descriptions/css/properties/animation-name.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "animation-name": { 5 | "__short_description": "The animation-name CSS property sets one or more animations to apply to an element. Each name is an @keyframes at-rule that sets the property values for the animation sequence." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/background-position.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "background-position": { 5 | "__short_description": "The background-position CSS property sets the initial position for each background image. The position is relative to the position layer set by background-origin." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/margin-top.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "margin-top": { 5 | "__short_description": "The margin-top CSS property sets the margin area on the top of an element. A positive value places it farther from its neighbors, while a negative value places it closer." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/background-position-y.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "background-position-y": { 5 | "__short_description": "The background-position-y CSS property sets the initial vertical position for each background image. The position is relative to the position layer set by background-origin." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/overflow.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "overflow": { 5 | "__short_description": "The overflow shorthand CSS property sets what to do when an element's content is too big to fit in its block formatting context." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/test-built-package.sh: -------------------------------------------------------------------------------- 1 | set -e 2 | 3 | # Validate that this package can be installed and it contains some data 4 | 5 | STARTING_DIR="$(pwd)" 6 | 7 | npm pack 8 | echo 9 | echo '✅ Package built!' 10 | echo 11 | 12 | cd "$(mktemp -d)" 13 | cp $STARTING_DIR/*.tgz . 14 | npm init --yes 15 | npm install *.tgz 16 | echo '✅ Package installed!' 17 | echo 18 | 19 | node -e 'typeof require("mdn-short-descriptions").css.properties.background.__short_description == "string" || process.exit(1)' 20 | echo '🏁 Package contained some data! 🏁' 21 | echo 22 | -------------------------------------------------------------------------------- /descriptions/css/properties/background-position-x.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "background-position-x": { 5 | "__short_description": "The background-position-x CSS property sets the initial horizontal position for each background image. The position is relative to the position layer set by background-origin." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/border-spacing.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "border-spacing": { 5 | "__short_description": "The border-spacing CSS property sets the distance between the borders of adjacent <table> cells. This property applies only when border-collapse is separate." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/align-content.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "align-content": { 5 | "__short_description": "The CSS align-content property sets the distribution of space between and around content items along a flexbox's cross-axis or a grid's block axis." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/caption-side.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "caption-side": { 5 | "__short_description": "The caption-side CSS property puts the content of a table's <caption> on the specified side. The values are relative to the writing-mode of the table." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/border-image-repeat.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "border-image-repeat": { 5 | "__short_description": "The border-image-repeat CSS property defines how the edge regions of a source image are adjusted to fit the dimensions of an element's border image." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/all.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "all": { 5 | "__short_description": "The all shorthand CSS property resets all of an element's properties (except unicode-bidi and direction)." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/border-image-slice.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "border-image-slice": { 5 | "__short_description": "The border-image-slice CSS property divides the image specified by border-image-source into regions. These regions form the components of an element's border image." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/border-right-color.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "border-right-color": { 5 | "__short_description": "The border-right-color CSS property sets the color of an element's right border. It can also be set with the shorthand CSS properties border-color or border-right." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/display.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "display": { 5 | "__short_description": "The display CSS property sets whether an element is treated as a block or inline element and the layout used for its children, such as grid or flex." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/align-self.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "align-self": { 5 | "__short_description": "The align-self CSS property overrides a grid or flex item's align-items value. In Grid, it aligns the item inside the grid area. In Flexbox, it aligns the item on the cross axis." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /descriptions/css/properties/position.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": { 3 | "properties": { 4 | "position": { 5 | "__short_description": "The position CSS property sets how an element is positioned in a document. The top, right, bottom, and left properties determine the final location of positioned elements." 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const extend = require('extend'); 2 | const fs = require('fs'); 3 | const path = require('path'); 4 | 5 | function walk(directory, callback) { 6 | fs.readdirSync(directory).forEach((filename) => { 7 | const filepath = path.join(directory, filename); 8 | 9 | if (fs.statSync(filepath).isDirectory()) { 10 | walk(filepath, callback); 11 | } 12 | callback(filepath); 13 | }); 14 | } 15 | 16 | function collectJSON(directory) { 17 | const filepaths = []; 18 | walk(directory, (fp) => { 19 | if (path.extname(fp) === '.json') { 20 | filepaths.push(fp); 21 | } 22 | }); 23 | return filepaths; 24 | } 25 | 26 | function loadJSON() { 27 | const jsons = collectJSON(path.resolve(__dirname, './descriptions')); 28 | const finalObj = {}; 29 | 30 | jsons.forEach((json) => { 31 | const nextObj = JSON.parse(fs.readFileSync(json, 'utf8')); 32 | extend(true, finalObj, nextObj); 33 | }); 34 | return finalObj; 35 | } 36 | 37 | module.exports = loadJSON(); 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This project is being superseded by other MDN projects. Check out https://github.com/mdn/stumptown-content for details. 2 | 3 | # [MDN short descriptions](https://github.com/mdn/short-descriptions) 4 | 5 | Formerly maintained by the [MDN team at Mozilla](https://wiki.mozilla.org/MDN). 6 | 7 | This project provides short, summary descriptions of technologies documented on 8 | [MDN](https://developer.mozilla.org/). In other words, we scrape MDN so you 9 | don't have to. 10 | 11 | ## License 12 | 13 | Prose from MDN, found in the `descriptions` directory, is by Mozilla 14 | Contributors and is licensed under [CC-BY-SA 15 | 2.5](http://creativecommons.org/licenses/by-sa/2.5/). You are free to modify and 16 | share that content, if you attribute the work and distribute it under the same 17 | terms. Visit [About 18 | MDN](https://developer.mozilla.org/en-US/docs/MDN/About#Using_MDN_Web_Docs_content) 19 | to learn more about MDN content, its authorship, and reuse. 20 | 21 | [The remainder of this repository is dedicated to the public domain (CC0 22 | 1.0)](http://creativecommons.org/publicdomain/zero/1.0/). To the extent 23 | possible under law, the contributors have waived all copyright and related or 24 | neighboring rights to MDN short descriptions. See the [LICENSE.txt](LICENSE.txt) file 25 | for details. 26 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mdn-short-descriptions", 3 | "version": "0.1.0", 4 | "description": "Short descriptions of web technologies from MDN Web Docs", 5 | "main": "index.js", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "dependencies": { 10 | "extend": "^3.0.2" 11 | }, 12 | "devDependencies": { 13 | "eslint": "^5.9.0", 14 | "eslint-config-airbnb-base": "^13.1.0", 15 | "eslint-plugin-import": "^2.14.0", 16 | "jsdom": "^12.2.0", 17 | "mdn-data": "^2.0.0", 18 | "request": "^2.88.0" 19 | }, 20 | "scripts": { 21 | "test": "node test/test.js && npm run lint-js && node test/json-format-rules.js && node test/content-rules.js && npm run lint-json", 22 | "lint-js": "eslint test/*.js scripts/*.js", 23 | "lint-json": "node test/lint-json.js", 24 | "lint-wiki": "node test/lint-wiki.js", 25 | "scrape": "node scripts/scrape.js" 26 | }, 27 | "repository": { 28 | "type": "git", 29 | "url": "git+https://github.com/mdn/short-descriptions.git" 30 | }, 31 | "keywords": [ 32 | "mozilla", 33 | "mdn", 34 | "data" 35 | ], 36 | "author": "MDN Web Docs", 37 | "license": "CC-BY-SA-2.5", 38 | "bugs": { 39 | "url": "https://github.com/mdn/short-descriptions/issues" 40 | }, 41 | "homepage": "https://github.com/mdn/short-descriptions#readme" 42 | } 43 | -------------------------------------------------------------------------------- /publishing-the-package.md: -------------------------------------------------------------------------------- 1 | # Publishing mdn-short-descriptions on npm 2 | 3 | Project owners can publish mdn-short-descriptions on npm by following these steps: 4 | 5 | 1. Figure out the next version number by looking at [past releases](https://github.com/mdn/short-descriptions/releases). The project is in alpha, so we're using only patch versions. 6 | 2. On an updated and clean master branch, `run npm version patch -m "Nth alpha version"`. Locally, this updates `package.json`, creates a new commit, and creates a new release tag (see the docs for [npm version](https://docs.npmjs.com/cli/version)). 7 | 3. Push the commit to master: `git push origin master`. 8 | 4. Check if the commit passes on [Travis CI](https://travis-ci.org/mdn/short-descriptions). 9 | 5. If Travis passes, push the git tag: `git push origin v0.0.X`. This step will trigger Travis to publish to npm automatically (see our [.travis.yml file](https://github.com/mdn/short-descriptions/blob/master/.travis.yml)). 10 | 6. Check [Travis CI](https://travis-ci.org/mdn/short-descriptions) again for the tag build and also check [mdn-short-descriptions on npm](https://www.npmjs.com/package/mdn-short-descriptions) to see if the release shows up correctly once Travis has finished its work. 11 | 7. Create a new [release on GitHub](https://github.com/mdn/short-descriptions/releases) and document changes. 12 | -------------------------------------------------------------------------------- /writing-short-descriptions.md: -------------------------------------------------------------------------------- 1 | # Writing short descriptions 2 | 3 | Short descriptions will be consistent with the following guidelines: 4 | 5 | * Short descriptions may be formatted with only the HTML tags ``, ``, ``, and ``.[1](#footnote1) 6 | * `` tags may use only on the `href` attribute pointing to absolute URLs.[1](#footnote1) 7 | * Short descriptions must not exceed 180 displayed (rendered) characters.[1](#footnote1) Optimally, they should be 100 to 120 characters. 8 | * The first sentence should be no more than 150 displayed characters.[1](#footnote1) 9 | * Short descriptions text should stand alone (e.g., it should not refer to text, images, or other content outside the short description). 10 | * Short descriptions must not mention support or standards status. 11 | * Short descriptions should mention relevant keywords and topic areas (e.g., a property that affects layout should mention the word "layout" and perhaps the model in which it applies, such as "grid"). 12 | * Short descriptions should avoid the use of words like "specifies", "defines", or "determines" when the word "sets" is just as good and results in no loss of meaning. 13 | * Short descriptions for shorthand properties should not name every property that they set. 14 | 15 | * Short descriptions should describe, in the active voice, what a CSS property does. "The `some-property` CSS property sets the …" is a good pattern for starting a short description. 16 | * Short descriptions should contain the name of the CSS property and the phrase "CSS property". 17 | * Short descriptions should use the word "shorthand" if the property is a shorthand and link to a page about shorthands. 18 | 19 | 1: Checked by linter on this repo. 20 | 21 | See https://github.com/mdn/data/issues/261 for details on how these guidelines were created. 22 | -------------------------------------------------------------------------------- /test/json-format-rules.js: -------------------------------------------------------------------------------- 1 | const assert = require('assert'); 2 | 3 | const ok = { passes: true, errors: [] }; 4 | 5 | const jsonFormatRules = [ 6 | { 7 | name: 'parseable', 8 | description: 'JSON must be parseable', 9 | bad: '{', 10 | good: '{}', 11 | check(source) { 12 | try { 13 | JSON.parse(source); 14 | return ok; 15 | } catch (err) { 16 | return { 17 | passes: false, 18 | errors: [`Could not parse as JSON: ${err}`], 19 | }; 20 | } 21 | }, 22 | }, 23 | { 24 | name: 'formatted', 25 | description: 'JSON should be formatted as in `JSON.stringify(, null, 2)`', 26 | bad: `{ 27 | "css": { 28 | "properties": { 29 | "align-content": { 30 | "__short_description": "" 31 | } 32 | } 33 | } 34 | }`, 35 | good: `{ 36 | "css": { 37 | "properties": { 38 | "align-content": { 39 | "__short_description": "" 40 | } 41 | } 42 | } 43 | }`, 44 | check(source) { 45 | const expected = `${JSON.stringify(JSON.parse(source), null, 2)}\n`; 46 | 47 | const actualLines = source.split('\n'); 48 | const expectedLines = expected.split('\n'); 49 | 50 | for (let i = 0; i < actualLines.length; i += 1) { 51 | if (actualLines[i] !== expectedLines[i]) { 52 | const result = { 53 | passes: false, 54 | errors: [ 55 | 'Unexpected JSON formatting', 56 | `Line ${i + 1} (Expected): ${expectedLines[i]}`, 57 | `Line ${i + 1} (Actual): \x1b[41m${actualLines[i]}\x1b[0m`, 58 | ], 59 | }; 60 | return result; 61 | } 62 | } 63 | 64 | return ok; 65 | }, 66 | }, 67 | ]; 68 | 69 | const testRules = () => { 70 | jsonFormatRules.forEach((rule) => { 71 | const good = rule.check(rule.good); 72 | const bad = rule.check(rule.bad); 73 | 74 | assert.ok(good.passes, `Expected \`true\` for result of "${rule.description}" good example.`); 75 | assert.deepStrictEqual(good.errors, [], `Expected 0 errors for "${rule.description}" good example.`); 76 | 77 | assert.ok(bad.passes === false, `Expected \`false\` for result of "${rule.description}" bad example.`); 78 | assert.ok(bad.errors.length > 0, `Expected errors for "${rule.description}" bad example.`); 79 | }); 80 | }; 81 | 82 | if (require.main === module) { 83 | testRules(); 84 | } 85 | 86 | module.exports = { jsonFormatRules }; 87 | -------------------------------------------------------------------------------- /test/lint-wiki.js: -------------------------------------------------------------------------------- 1 | // Examples: 2 | // Check the color property page summary on MDN Web Docs: 3 | // $ npm run lint-short-descriptions color 4 | // Check the color and background-color properties' page summaries on MDN 5 | // $ npm run lint-short-descriptions color background-color 6 | // Check the contents of standard input as if it were a short description 7 | // $ npm run lint-short-descriptions - 8 | 9 | const readline = require('readline'); 10 | 11 | const jsdom = require('jsdom'); 12 | const { properties } = require('mdn-data').css; 13 | const { contentRules, fragmentToDom } = require('./content-rules'); 14 | 15 | const excludedRules = ['no-nbsps', 'no-forbidden-attrs']; 16 | const wikiRules = contentRules.filter(rule => !excludedRules.includes(rule.name)); 17 | 18 | const nameToURL = (property) => { 19 | // turn a CSS property name into an raw MDN page summary URL 20 | if (properties[property] === undefined) { 21 | console.error(`${property} is not a known CSS property in mdn-data`); 22 | process.exit(1); 23 | } 24 | 25 | if (properties[property].mdn_url === undefined) { 26 | console.error(`${property} does not have an MDN URL in mdn-data`); 27 | process.exit(1); 28 | } 29 | 30 | const cacheBuster = Math.random().toString(36).substr(2, 5); 31 | return `${properties[property].mdn_url}?raw&summary&${cacheBuster}`; 32 | }; 33 | 34 | const stdinToDom = () => new Promise((resolve) => { 35 | const rl = readline.createInterface({ 36 | input: process.stdin, 37 | output: process.stdout, 38 | terminal: false, 39 | }); 40 | const lines = []; 41 | 42 | rl.on('line', line => lines.push(line)); 43 | rl.on('close', () => resolve(fragmentToDom(lines))); 44 | }); 45 | 46 | const urlToDom = async url => (await jsdom.JSDOM.fromURL(url)).window.document.querySelector('body'); 47 | 48 | const checkSummary = (dom, propertyName, url) => { 49 | wikiRules.forEach((rule) => { 50 | const result = rule.check(dom); 51 | 52 | if (!result.passes) { 53 | result.errors.forEach(e => console.error(`${propertyName} (${url}): ${e}`)); 54 | } 55 | }); 56 | }; 57 | 58 | const main = (args) => { 59 | const sequence = []; 60 | 61 | args.forEach((arg) => { 62 | let url; 63 | let dom; 64 | 65 | if (arg === '-') { 66 | url = 'no URL'; 67 | dom = stdinToDom(); 68 | } else { 69 | url = nameToURL(arg); 70 | dom = urlToDom(url); 71 | } 72 | 73 | sequence.push({ 74 | prop: arg, 75 | url, 76 | dom, 77 | }); 78 | }); 79 | 80 | sequence.forEach(async (item) => { 81 | const dom = await item.dom; 82 | checkSummary(dom, item.prop, item.url); 83 | }); 84 | }; 85 | 86 | const cli = () => main(process.argv.slice(2)); 87 | 88 | if (require.main === module) { 89 | cli(); 90 | } 91 | -------------------------------------------------------------------------------- /test/lint-json.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | const { jsonFormatRules } = require('./json-format-rules'); 4 | const { contentRules, fragmentToDom } = require('./content-rules'); 5 | 6 | const walk = (directory, callback) => { 7 | fs.readdirSync(directory).forEach((filename) => { 8 | const filepath = path.join(directory, filename); 9 | 10 | if (fs.statSync(filepath).isDirectory()) { 11 | walk(filepath, callback); 12 | } 13 | callback(filepath); 14 | }); 15 | }; 16 | 17 | const collectJSON = (directory) => { 18 | const filepaths = []; 19 | walk(directory, (fp) => { 20 | if (path.extname(fp) === '.json') { 21 | filepaths.push(fp); 22 | } 23 | }); 24 | return filepaths; 25 | }; 26 | 27 | const lintSource = (filepath, data) => { 28 | let passes = true; 29 | 30 | for (let index = 0; index < jsonFormatRules.length; index += 1) { 31 | const rule = jsonFormatRules[index]; 32 | const result = rule.check(data); 33 | 34 | if (!result.passes) { 35 | result.errors.forEach(e => console.error(`${filepath}: ${e}`)); 36 | passes = false; 37 | break; 38 | } 39 | } 40 | 41 | return passes; 42 | }; 43 | 44 | const lintContent = (filepath, dom) => { 45 | let passes = true; 46 | 47 | contentRules.forEach((rule) => { 48 | const result = rule.check(dom); 49 | 50 | if (!result.passes) { 51 | result.errors.forEach(e => console.error(`${filepath}: ${e}`)); 52 | passes = false; 53 | } 54 | }); 55 | 56 | return passes; 57 | }; 58 | 59 | const main = () => { 60 | const jsonFiles = collectJSON('./descriptions'); 61 | 62 | const results = jsonFiles.map((filepath) => { 63 | const data = fs.readFileSync(filepath, 'utf8'); 64 | const sourcePasses = lintSource(filepath, data); 65 | 66 | if (!sourcePasses) { 67 | console.error(`${filepath}: source checks didn't pass. Skipping content checks.`); 68 | return { 69 | filepath, success: false, sourcePasses: false, contentPasses: null, 70 | }; 71 | } 72 | 73 | const json = JSON.parse(data); 74 | const propName = Object.keys(json.css.properties)[0]; 75 | // eslint-disable-next-line no-underscore-dangle 76 | const description = json.css.properties[propName].__short_description; 77 | 78 | const contentPasses = lintContent(filepath, fragmentToDom(description)); 79 | return { 80 | filepath, success: sourcePasses && contentPasses, sourcePasses, contentPasses, 81 | }; 82 | }); 83 | 84 | const successes = []; 85 | const failures = []; 86 | results.forEach(result => (result.success ? successes.push(result) : failures.push(result))); 87 | 88 | console.log(`\nChecked ${results.length} descriptions.`); 89 | console.log(`${successes.length} descriptions passed all checks.`); 90 | 91 | if (failures.length) { 92 | console.log(`${failures.length} descriptions failed one or more checks:`); 93 | failures.forEach(result => console.log(` ${result.filepath}`)); 94 | process.exit(1); 95 | } 96 | }; 97 | 98 | if (require.main === module) { 99 | main(); 100 | } 101 | -------------------------------------------------------------------------------- /scripts/scrape.js: -------------------------------------------------------------------------------- 1 | // Examples: 2 | // Scrape the color property page summary on MDN Web Docs to JSON: 3 | // $ npm run scrape color 4 | // Scrape the color and background-color property page summaries: 5 | // $ npm run scrape color background-color 6 | // Scrape all the summaries for ALL the property pages known to mdn/data: 7 | // $ npm run scrape 8 | 9 | const fs = require('fs'); 10 | const path = require('path'); 11 | 12 | const { properties } = require('mdn-data').css; 13 | const jsdom = require('jsdom'); 14 | 15 | const allProperties = Object.keys(properties); 16 | 17 | const allowed = { 18 | A: ['href'], 19 | CODE: [], 20 | EM: [], 21 | STRONG: [], 22 | }; 23 | 24 | // For limiting requests to the wiki, since it doesn't seem to like it when you make hundreds of 25 | // requests at once. 26 | const delay = timeout => new Promise(resolve => setTimeout(resolve, timeout)); 27 | 28 | const summarize = (url) => { 29 | // Add raw, summary, and cache-busting query parameters to a wiki page URL 30 | const cacheBuster = Math.random().toString(36).substr(2, 5); 31 | return `${url}?raw&summary&${cacheBuster}`; 32 | }; 33 | 34 | const delocalize = (aElem) => { 35 | // Remove the localization path from a wiki page URL (and only wiki page URLs) 36 | const a = aElem; 37 | 38 | if (a.hostname === 'developer.mozilla.org') { 39 | const pathComponents = a.pathname.split('/'); 40 | if (pathComponents[1] !== 'docs') { 41 | pathComponents.splice(1, 1); 42 | a.pathname = pathComponents.join('/'); 43 | } 44 | } 45 | }; 46 | 47 | const abs = (aElem) => { 48 | // Make an A element's href attribute absolute 49 | const a = aElem; 50 | 51 | // An element's href property returns an absolute URL, but innerHTML seralizes a relative URL. 52 | // The next line looks like it does nothing, but it replaces a relative URL with an absolute. 53 | a.href = a.href; 54 | }; 55 | 56 | const domTransforms = [ 57 | function cleanLinks(dom) { 58 | dom.window.document.querySelectorAll('BODY A').forEach((elem) => { 59 | abs(elem); 60 | delocalize(elem); 61 | }); 62 | 63 | return dom; 64 | }, 65 | 66 | function stripUnwantedAttrs(dom) { 67 | dom.window.document.querySelectorAll('BODY *').forEach((elem) => { 68 | const allowedAttrs = allowed[elem.tagName]; 69 | 70 | if (allowedAttrs !== undefined) { 71 | Array.from(elem.attributes).forEach((attr) => { 72 | if (!allowedAttrs.includes(attr.name)) { 73 | elem.removeAttribute(attr.name); 74 | } 75 | }); 76 | } 77 | }); 78 | return dom; 79 | }, 80 | 81 | function toHTML(dom) { return dom.window.document.querySelector('BODY').innerHTML; }, 82 | ]; 83 | 84 | const htmlTransforms = [ 85 | function replaceDoubleQuotes(html) { return html.replace(/"/g, "'"); }, 86 | function removeNbsps(html) { return html.replace(/ /g, ' '); }, 87 | ]; 88 | 89 | const writeToFile = (propertyName, html) => { 90 | const data = { 91 | css: { 92 | properties: { 93 | [propertyName]: { 94 | __short_description: html, 95 | }, 96 | }, 97 | }, 98 | }; 99 | 100 | const dest = path.join(__dirname, '../descriptions/css/properties/', `${propertyName}.json`); 101 | const destDir = path.dirname(dest); 102 | if (!fs.existsSync(destDir)) { 103 | fs.mkdirSync(path.dirname(destDir), { recursive: true }); 104 | } 105 | fs.writeFileSync(dest, `${JSON.stringify(data, null, 2)}\n`); 106 | }; 107 | 108 | const main = async (args) => { 109 | const props = args.length === 0 ? allProperties : args; 110 | 111 | const propPipelines = props.map(async (propName, index) => { 112 | const property = properties[propName]; 113 | 114 | if (property === undefined) { 115 | return { success: false, name: propName, error: 'Property not found' }; 116 | } 117 | 118 | const url = property.mdn_url; 119 | if (url === undefined) { 120 | return { success: false, name: propName, error: 'No `mdn_url` found' }; 121 | } 122 | 123 | try { 124 | await delay(index * 500); 125 | const dom = await jsdom.JSDOM.fromURL(summarize(url)); 126 | 127 | const html = domTransforms.reduce((domObj, fn) => fn(domObj), dom); 128 | const final = htmlTransforms.reduce((htmlObj, fn) => fn(htmlObj), html); 129 | 130 | writeToFile(propName, final); 131 | return { success: true, name: propName }; 132 | } catch (err) { 133 | console.trace(err); 134 | return ({ success: false, name: propName, error: err }); 135 | } 136 | }); 137 | 138 | const results = await Promise.all(propPipelines); 139 | 140 | const successes = []; 141 | const failures = []; 142 | results.forEach(result => (result.success ? successes.push(result) : failures.push(result))); 143 | 144 | console.log(`\nAttempted to scrape ${results.length} properties.`); 145 | console.log(`Successfully scraped ${successes.length} properties.`); 146 | 147 | if (failures.length) { 148 | console.log(`Failed to scrape ${failures.length} properties:`); 149 | failures.forEach(result => console.log(` ${result.name}: ${result.error}`)); 150 | } 151 | }; 152 | 153 | const cli = () => { 154 | main(process.argv.slice(2)); 155 | }; 156 | 157 | cli(); 158 | -------------------------------------------------------------------------------- /test/content-rules.js: -------------------------------------------------------------------------------- 1 | const assert = require('assert'); 2 | const jsdom = require('jsdom'); 3 | 4 | const maxLength = 180; 5 | const maxFirstSentenceLength = 150; 6 | const allowedTags = { 7 | A: ['href'], 8 | CODE: [], 9 | EM: [], 10 | STRONG: [], 11 | }; 12 | 13 | const fragmentToDom = html => (new jsdom.JSDOM(html)).window.document.querySelector('body'); 14 | 15 | const forbiddenTags = (dom) => { 16 | const tagSet = new Set(); 17 | dom.querySelectorAll('*').forEach(elem => tagSet.add(elem.tagName)); 18 | return Array.from(tagSet).filter(v => !Object.keys(allowedTags).includes(v)); 19 | }; 20 | 21 | const forbiddenAttrs = (dom) => { 22 | const badAttrs = []; 23 | 24 | dom.querySelectorAll('*').forEach((elem) => { 25 | const allowedAttrs = allowedTags[elem.tagName] || []; 26 | 27 | const attrNames = Array.from(elem.attributes).map(value => value.name); 28 | attrNames.filter(attr => !allowedAttrs.includes(attr)) 29 | .forEach(attr => badAttrs.push(`${elem.tagName}.${attr}`)); 30 | }); 31 | 32 | return badAttrs; 33 | }; 34 | 35 | const ok = { passes: true, errors: [] }; 36 | 37 | const contentRules = [ 38 | { 39 | name: 'max-sentence-length', 40 | description: `First sentence should not exceed ${maxFirstSentenceLength} characters`, 41 | bad: 'This is a very, very, very, very, very, very, very, very, very, very, very, very, very, very, very, very, very, very, very, very, very, very, very, very long first sentence. This is the second sentence.', 42 | good: 'This is a short first sentence. This is the second sentence.', 43 | check(dom) { 44 | const firstSentence = dom.textContent.replace(/\.(?!\d)/g, '.\x1f').split('\x1f')[0]; 45 | 46 | const passes = firstSentence.length <= maxFirstSentenceLength; 47 | 48 | if (passes) { 49 | return ok; 50 | } 51 | return { 52 | passes, 53 | errors: [ 54 | `First sentence may be too long. Expected ≤${maxFirstSentenceLength}; got ${firstSentence.length}`, 55 | `> ${firstSentence.slice(0, maxFirstSentenceLength)}\x1b[41m${firstSentence.slice(maxFirstSentenceLength)}\x1b[0m`, 56 | ], 57 | }; 58 | }, 59 | }, 60 | { 61 | name: 'max-length', 62 | description: `Overall length should not exceed ${maxLength} characters`, 63 | bad: "This is an example. This is an example. This is an example. This is an example. This is an example. This is an example. This is an example. This is an example. This is an example. But now we've gone on too long.", 64 | good: 'This is short and sweet.', 65 | check(dom) { 66 | const text = dom.textContent; 67 | const passes = text.length <= maxLength; 68 | 69 | if (passes) { 70 | return ok; 71 | } 72 | return { 73 | passes, 74 | errors: [ 75 | `Summary is too long. Expected ≤${maxLength} characters; got ${text.length}`, 76 | `> ${text.slice(0, maxLength)}\x1b[41m${text.slice(maxLength)}\x1b[0m`, 77 | ], 78 | }; 79 | }, 80 | }, 81 | { 82 | name: 'no-nbsps', 83 | description: '" " shouldn\'t be used', 84 | bad: 'Use literal spaces.', 85 | good: 'Use literal spaces.', 86 | check(dom) { 87 | const html = dom.innerHTML; 88 | 89 | const passes = !html.includes(' '); 90 | 91 | if (passes) { 92 | return ok; 93 | } 94 | return { 95 | passes, 96 | errors: [ 97 | 'Contains ` ` instead of literal spaces.', 98 | `> ${html.replace(/ /g, '\x1b[41m \x1b[0m')}`, 99 | ], 100 | }; 101 | }, 102 | }, 103 | { 104 | name: 'no-forbidden-tags', 105 | description: 'Only use allowed tags', 106 | bad: "
I am a poet
and didn't even know it.
", 107 | good: "I am a poet and didn't even know it.", 108 | check(dom) { 109 | const badTags = forbiddenTags(dom); 110 | 111 | const passes = badTags.length === 0; 112 | 113 | if (passes) { 114 | return ok; 115 | } 116 | 117 | const badElems = dom.querySelectorAll(badTags.join(', ')); 118 | const badHTML = [...badElems].map(elem => `> ${elem.parentNode.innerHTML}`); 119 | const errors = [ 120 | `Contains forbidden tags: \x1b[41m${badTags.join(', ')}\x1b[0m`, 121 | ...badHTML, 122 | ]; 123 | 124 | return { 125 | passes, 126 | errors, 127 | }; 128 | }, 129 | }, 130 | { 131 | name: 'no-forbidden-attrs', 132 | description: 'Only use allowed attributes', 133 | bad: 'This has two bad attributes: MDN Web Docs
', 134 | good: 'MDN Web Docs', 135 | check(dom) { 136 | const badAttrs = forbiddenAttrs(dom); 137 | 138 | const passes = badAttrs.length === 0; 139 | 140 | if (passes) { 141 | return ok; 142 | } 143 | return { 144 | passes, 145 | errors: [ 146 | `Contains forbidden attributes: \x1b[41m${badAttrs.join(', ')}\x1b[0m`, 147 | ], 148 | }; 149 | }, 150 | }, 151 | ]; 152 | 153 | const testRules = () => { 154 | contentRules.forEach((rule) => { 155 | const good = rule.check(fragmentToDom(rule.good)); 156 | const bad = rule.check(fragmentToDom(rule.bad)); 157 | 158 | assert.ok(good.passes, `Expected \`true\` for result of "${rule.description}" good example.`); 159 | assert.deepStrictEqual(good.errors, [], `Expected 0 errors for "${rule.description}" good example.`); 160 | 161 | assert.ok(bad.passes === false, `Expected \`false\` for result of "${rule.description}" bad example.`); 162 | assert.ok(bad.errors.length > 0, `Expected errors for "${rule.description}" bad example.`); 163 | }); 164 | }; 165 | 166 | if (require.main === module) { 167 | testRules(); 168 | } 169 | 170 | module.exports = { 171 | contentRules, 172 | fragmentToDom, 173 | }; 174 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | NOTE: the following text does not apply to MDN prose content in the 2 | descriptions directory. See README.md and descriptions/LICENSE.md for 3 | details. 4 | 5 | Creative Commons Legal Code 6 | 7 | CC0 1.0 Universal 8 | 9 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE 10 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN 11 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS 12 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES 13 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS 14 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM 15 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED 16 | HEREUNDER. 17 | 18 | Statement of Purpose 19 | 20 | The laws of most jurisdictions throughout the world automatically confer 21 | exclusive Copyright and Related Rights (defined below) upon the creator 22 | and subsequent owner(s) (each and all, an "owner") of an original work of 23 | authorship and/or a database (each, a "Work"). 24 | 25 | Certain owners wish to permanently relinquish those rights to a Work for 26 | the purpose of contributing to a commons of creative, cultural and 27 | scientific works ("Commons") that the public can reliably and without fear 28 | of later claims of infringement build upon, modify, incorporate in other 29 | works, reuse and redistribute as freely as possible in any form whatsoever 30 | and for any purposes, including without limitation commercial purposes. 31 | These owners may contribute to the Commons to promote the ideal of a free 32 | culture and the further production of creative, cultural and scientific 33 | works, or to gain reputation or greater distribution for their Work in 34 | part through the use and efforts of others. 35 | 36 | For these and/or other purposes and motivations, and without any 37 | expectation of additional consideration or compensation, the person 38 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she 39 | is an owner of Copyright and Related Rights in the Work, voluntarily 40 | elects to apply CC0 to the Work and publicly distribute the Work under its 41 | terms, with knowledge of his or her Copyright and Related Rights in the 42 | Work and the meaning and intended legal effect of CC0 on those rights. 43 | 44 | 1. Copyright and Related Rights. A Work made available under CC0 may be 45 | protected by copyright and related or neighboring rights ("Copyright and 46 | Related Rights"). Copyright and Related Rights include, but are not 47 | limited to, the following: 48 | 49 | i. the right to reproduce, adapt, distribute, perform, display, 50 | communicate, and translate a Work; 51 | ii. moral rights retained by the original author(s) and/or performer(s); 52 | iii. publicity and privacy rights pertaining to a person's image or 53 | likeness depicted in a Work; 54 | iv. rights protecting against unfair competition in regards to a Work, 55 | subject to the limitations in paragraph 4(a), below; 56 | v. rights protecting the extraction, dissemination, use and reuse of data 57 | in a Work; 58 | vi. database rights (such as those arising under Directive 96/9/EC of the 59 | European Parliament and of the Council of 11 March 1996 on the legal 60 | protection of databases, and under any national implementation 61 | thereof, including any amended or successor version of such 62 | directive); and 63 | vii. other similar, equivalent or corresponding rights throughout the 64 | world based on applicable law or treaty, and any national 65 | implementations thereof. 66 | 67 | 2. Waiver. To the greatest extent permitted by, but not in contravention 68 | of, applicable law, Affirmer hereby overtly, fully, permanently, 69 | irrevocably and unconditionally waives, abandons, and surrenders all of 70 | Affirmer's Copyright and Related Rights and associated claims and causes 71 | of action, whether now known or unknown (including existing as well as 72 | future claims and causes of action), in the Work (i) in all territories 73 | worldwide, (ii) for the maximum duration provided by applicable law or 74 | treaty (including future time extensions), (iii) in any current or future 75 | medium and for any number of copies, and (iv) for any purpose whatsoever, 76 | including without limitation commercial, advertising or promotional 77 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each 78 | member of the public at large and to the detriment of Affirmer's heirs and 79 | successors, fully intending that such Waiver shall not be subject to 80 | revocation, rescission, cancellation, termination, or any other legal or 81 | equitable action to disrupt the quiet enjoyment of the Work by the public 82 | as contemplated by Affirmer's express Statement of Purpose. 83 | 84 | 3. Public License Fallback. Should any part of the Waiver for any reason 85 | be judged legally invalid or ineffective under applicable law, then the 86 | Waiver shall be preserved to the maximum extent permitted taking into 87 | account Affirmer's express Statement of Purpose. In addition, to the 88 | extent the Waiver is so judged Affirmer hereby grants to each affected 89 | person a royalty-free, non transferable, non sublicensable, non exclusive, 90 | irrevocable and unconditional license to exercise Affirmer's Copyright and 91 | Related Rights in the Work (i) in all territories worldwide, (ii) for the 92 | maximum duration provided by applicable law or treaty (including future 93 | time extensions), (iii) in any current or future medium and for any number 94 | of copies, and (iv) for any purpose whatsoever, including without 95 | limitation commercial, advertising or promotional purposes (the 96 | "License"). The License shall be deemed effective as of the date CC0 was 97 | applied by Affirmer to the Work. Should any part of the License for any 98 | reason be judged legally invalid or ineffective under applicable law, such 99 | partial invalidity or ineffectiveness shall not invalidate the remainder 100 | of the License, and in such case Affirmer hereby affirms that he or she 101 | will not (i) exercise any of his or her remaining Copyright and Related 102 | Rights in the Work or (ii) assert any associated claims and causes of 103 | action with respect to the Work, in either case contrary to Affirmer's 104 | express Statement of Purpose. 105 | 106 | 4. Limitations and Disclaimers. 107 | 108 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 109 | surrendered, licensed or otherwise affected by this document. 110 | b. Affirmer offers the Work as-is and makes no representations or 111 | warranties of any kind concerning the Work, express, implied, 112 | statutory or otherwise, including without limitation warranties of 113 | title, merchantability, fitness for a particular purpose, non 114 | infringement, or the absence of latent or other defects, accuracy, or 115 | the present or absence of errors, whether or not discoverable, all to 116 | the greatest extent permissible under applicable law. 117 | c. Affirmer disclaims responsibility for clearing rights of other persons 118 | that may apply to the Work or any use thereof, including without 119 | limitation any person's Copyright and Related Rights in the Work. 120 | Further, Affirmer disclaims responsibility for obtaining any necessary 121 | consents, permissions or other rights required for any use of the 122 | Work. 123 | d. Affirmer understands and acknowledges that Creative Commons is not a 124 | party to this document and has no duty or obligation with respect to 125 | this CC0 or use of the Work. 126 | -------------------------------------------------------------------------------- /project-overview.md: -------------------------------------------------------------------------------- 1 | This document describes the project to make "CSS short descriptions" available to third-party tools such as code editors or developer tools. 2 | 3 | The "short description" is the opening sentence or two of a CSS property reference page. It gives a very short overview of the property. It's also known as a summary. 4 | 5 | It follows a reasonably consistent pattern: 6 | 7 | > The **`foo`** [CSS](https://developer.mozilla.org/CSS) property is... It is related to the [`bar`](https://developer.mozilla.org/docs/Web/CSS/bar) property... 8 | 9 | For example: 10 | 11 | > The **`box-shadow`** [CSS](https://developer.mozilla.org/CSS) property is used to add shadow effects around an element's frame. You can specify multiple effects separated by commas if you wish to do so. A box shadow is described by X and Y offsets relative to the element, blur and spread radii, and color. 12 | 13 | > The **`margin`** [CSS](https://developer.mozilla.org/CSS) property sets the margin area on all four sides of an element. It is a shorthand for setting all individual margins at once: [`margin-top`](https://developer.mozilla.org/docs/Web/CSS/margin-top), [`margin-right`](https://developer.mozilla.org/docs/Web/CSS/margin-right), [`margin-bottom`](https://developer.mozilla.org/docs/Web/CSS/margin-bottom), and [`margin-left`](https://developer.mozilla.org/docs/Web/CSS/margin-left). 14 | 15 | Currently the short description is just part of the Wiki document for the property. It's been proposed (e.g. https://github.com/mdn/data/issues/199) to include the short description in the JSON data structures in the [mdn/data](https://github.com/mdn/data/) GitHub repository. 16 | 17 | The rationale for doing this is that it makes it much easier for external tools to embed the short description. For example, an editor like VSCode could fetch the short description and display it in a contextual popup along with other useful information like browser compatibility. External tools can (and do) do this already by scraping the Wiki, but this is quite unreliable. 18 | 19 | The rest of this document is split into the following sections: 20 | 21 | * **Interface**: this describes, at a high level, how third party tools will be presented with short descriptions. 22 | * **Implementation**: this describes what we will do under the surface, to implement this interface. 23 | * **Work items**: this starts to break down the things that need to happen in the implementation. 24 | 25 | ## Interface 26 | 27 | **Note that the public interface of this project is at a very early stage and is (very) subject to change.** 28 | 29 | ### Initial proposal 30 | 31 | Our initial proposal was to import CSS short descriptions from the MDN wiki and into the [mdn/data](https://github.com/mdn/data/) GitHub repository. This repository is published as an npm package, [mdn-data](https://www.npmjs.com/package/mdn-data), and this could be used by third parties to access short descriptions, just as it is currently used by third parties to access CSS syntax. 32 | 33 | We don't think this is a viable approach any more, because mdn/data is published under the CC0 license, while [MDN prose content is published under the CC-BY-SA license](https://developer.mozilla.org/en-US/docs/MDN/About#Copyrights_and_licenses). 34 | 35 | ### Current proposal 36 | 37 | The current proposal is to create a new GitHub repository called mdn/short-descriptions. This contains the CSS short descriptions scraped from the Wiki under a CC-BY-SA. 38 | 39 | We would then publish a new npm package that *combines* the data from mdn/data and the content from mdn/short-descriptions. This package would be CC-BY-SA licensed and called "mdn-docs". 40 | 41 | ``` 42 | GitHub npm 43 | ------------------------------------------------------ 44 | ___________________ 45 | | | 46 | mdn/data------------------>| mdn-data (CC0) | 47 | (CC0) | |_________________| 48 | | 49 | | _______________________ 50 | -------------->| | 51 | | mdn-docs (CC-BY-SA) | 52 | mdn/short-descriptions --->|_____________________| 53 | (CC-BY-SA) 54 | 55 | ``` 56 | 57 | The internal structure of this new package would copy the structure used in [browser-compat-data](https://github.com/mdn/browser-compat-data). For example, you could access the short description for the `margin` property using a query like: 58 | 59 | `css.properties.margin.__docs.short_description` 60 | 61 | Open questions: 62 | * What should the npm package be called? `mdn-docs`? `mdn-content`? `mdn-short-descriptions`? 63 | * Should the npm package include the contents of mdn/data, or not? That is, should we provide one place where consumers can get data and short descriptions, or should we make them separate packages? 64 | * Should we in general move towards a common way to organize npm packages? Meaning, should we aim to restructure mdn/data to follow the "BCD structure"? 65 | 66 | ## Implementation 67 | 68 | This section describes what happens under the surface: how we will arrange for the publication of an npm package containing short descriptions, that have been validated to ensure they meet our guidelines. 69 | 70 | One major decision we've made is: the source for the short descriptions will continue to be the MDN Wiki pages. That is, we won't copy them from the Wiki once and then maintain them on GitHub. Instead, we will copy them and then update them from the MDN Wiki whenever we want to make a new release. The contribution workflow for CSS short descriptions will ontinue to be the Wiki. For background on this decision, see [this Discourse thread](https://discourse.mozilla.org/t/proposal-including-css-short-descriptions-in-mdn-data/30500/). 71 | 72 | In a little more detail, here's how we expect this to work: 73 | 74 | * Define guidelines for CSS short descriptions: how long they should be, what sort of content they should contain, and so on. Some of these can be checked by a linter, some need a human. 75 | * Update all the MDN Wiki pages so they meet these guidelines. 76 | * Scrape short descriptions from the Wiki into the `mdn/short-descriptions` GitHub repo. 77 | * Publish the `mdn-docs` npm package that combines `mdn/short-descriptions` and `mdn/data`. 78 | 79 | Subsequently, on a regular schedule: 80 | 81 | * Scrape the MDN Wiki for updated short descriptions. 82 | * If any short descriptions are new or changed, do some automated linting against our guidelines. 83 | * If there are errors here, manually fix them by editing the Wiki pages and try again. 84 | * When there are no linting errors, prepare a PR against `mdn/short-descriptions` that updates the content with the changes from the MDN Wiki. 85 | * Review the PR manually. If there are any problems, manually fix them by editing the Wiki pages and try again. 86 | * Once the PR looks good, merge it into `mdn/short-descriptions` and publish a new version of the npm `mdn-docs` package. 87 | 88 | ## Work items 89 | 90 | * Create the short-descriptions repo, with the appropriate basic docs (README, LICENSE). 91 | * Write a document describing guidelines for CSS short descriptions, and add it to the repo. 92 | * Write a schema for the repo defining the structure of the content it contains. 93 | * Update the CSS short descriptions in the Wiki so they meet our documented guidelines. 94 | * Write a script that can: 95 | * fetch CSS short descriptions from MDN Wiki pages 96 | * if the short description does not already exist in the GitHub repo, or does not match the one in the GitHub repo, then: 97 | * validate the text from the Wiki against the guidelines, as far as that's practical in a script. If there is an error, log it. Otherwise add the new description to a changelist. 98 | * create a PR for mdn/short-descriptions that includes all changelists. 99 | * Write a script that can create a new release of the `mdn-docs` npm package, from the short descriptions in `mdn/short-descriptions` and the data in `mdn/data`. 100 | --------------------------------------------------------------------------------