├── .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 quotesCSS 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-sizeCSS 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": "Theborder-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 columnsCSS 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-colorCSS 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-widthCSS 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-sizingCSS 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-spacingCSS 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-spacingCSS 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-imageCSS 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-widthCSS 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-alignCSS 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-stateCSS 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-widthCSS 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-widthCSS 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 cursorCSS 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 flexCSS 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-durationCSS 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 CSSjustify-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-heightCSS 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 bordershorthandCSS 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-shadowCSS 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-modeCSS 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-functionCSS 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": "Thelist-style-typeCSS 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-directionCSS 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-originCSS 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-countCSS 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 animationshorthandCSS 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-colorshorthandCSS 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-widthshorthandCSS 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-afterCSS 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-widthCSS 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-beforeCSS 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-insideCSS 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 CSSalign-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-modeCSS 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-imageCSS 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": "Thepadding-rightCSS 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-styleCSS 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-styleCSS 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-styleshorthandCSS 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-overflowCSS 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-delayCSS 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-styleCSS 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-decorationshorthandCSS 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-repeatCSS 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-sizeCSS 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-sourceCSS 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-radiusCSS 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 bottomCSS 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-collapseCSS 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-topshorthandCSS 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-outsetCSS 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-leftshorthandCSS 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 backgroundshorthandCSS 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-rightshorthandCSS 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-weightCSS 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-bottomshorthandCSS 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-eventsCSS 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 transformCSS 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-attachmentCSS 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-nameCSS 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-positionCSS 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-topCSS 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-yCSS 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 overflowshorthandCSS 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-xCSS 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 CSSalign-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-sideCSS 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-repeatCSS 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 allshorthandCSS 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-sliceCSS 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 displayCSS 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-selfCSS 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 positionCSS 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 |
--------------------------------------------------------------------------------