const _ = require('lodash'); const oneLineTrim = require('common-tags/lib/oneLineTrim'); const previousSpec = require('./v1'); const ghostVersions = require('../utils').versions; const docsBaseUrl = `https://ghost.org/docs/themes/`; // TODO: we don't use versioned docs anymore and the previous rules should only contain // correct links. The usage of replacing the previousBaseUrl can probably be removed const prevDocsBaseUrl = `https://themes.ghost.org/v${ghostVersions.v1.docs}/docs/`; const prevDocsBaseUrlRegEx = new RegExp(prevDocsBaseUrl, 'g'); const previousKnownHelpers = previousSpec.knownHelpers; const previousTemplates = previousSpec.templates; const previousRules = previousSpec.rules; function requiredClassRule(strings) { return `The .${strings[0]} CSS class is required to appear styled in your theme`; } function requiredClassDetails(strings) { return oneLineTrim`The .${strings[0]} CSS class is required otherwise wide images will appear unstyled. Find out more about required theme changes for the Koenig editor here.`; } // assign new or overwrite existing knownHelpers, templates, or rules here: let knownHelpers = ['link', 'link_class', 'concat']; let templates = []; let rules = { // New rules 'GS001-DEPR-USER-GET': { level: 'error', rule: `Replace {{#get "users"}} with {{#get "authors"}}`, details: oneLineTrim`The usage of {{#get "users"}} is deprecated and will not return any data. It should be replaced with {{#get "authors"}}.
Find more information about the {{get}} helper here.`, regex: /{{\s*?#get ("|')\s*users("|')\s*/g, helper: '{{#get "users"}}' }, 'GS001-DEPR-AUTH-INCL': { level: 'error', rule: `Replace include="author" with include="authors"`, details: oneLineTrim`The usage of {{#get "posts" include="author"}} is deprecated and should be replaced with {{#get "posts" include="authors"}}.
Find more information about the {{get}} helper here.`, // This regex seems only to work properly with the escaped characters. Removing them resulted // in not detecting the wrong usage. regex: /{{\s*?#get.+include=("|')\s*?([\w\[\]]+,{1}\s*?)*?(\s*?author\s*?)(\s*,{1}\s?[\w\[\]]+)*?\s*?("|')(.*)}}/g, // eslint-disable-line no-useless-escape helper: 'include="author"' }, 'GS001-DEPR-AUTH-FIELD': { level: 'error', rule: `Replace fields="author" with fields="authors"`, details: oneLineTrim`The usage of {{#get "posts" fields="author"}} is deprecated and should be replaced with {{#get "posts" fields="primary_author"}} or {{#get "posts" fields="authors.[#]"}}.
Find more information about the {{get}} helper here.`, // This regex seems only to work properly with the escaped characters. Removing them resulted // in not detecting the wrong usage. regex: /{{\s*?#get.+fields=("|')\s*?([\w\[\]]+,{1}\s*?)*?(\s*?author\s*?)(\s*,{1}\s?[\w\[\]]+)*?\s*?("|')(.*)}}/g, // eslint-disable-line no-useless-escape helper: 'fields="author"' }, 'GS001-DEPR-AUTH-FILT': { level: 'error', rule: `Replace filter="author:[...]" with filter="authors:[...]"`, details: oneLineTrim`The usage of {{#get "posts" filter="author:[...]"}} is deprecated and should be replaced with {{#get "posts" filter="authors:[...]"}}.
Find more information about the {{get}} helper here.`, // This regex seems only to work properly with the escaped characters. Removing them resulted // in not detecting the wrong usage. regex: /{{\s*?#get.+filter=("|')\s*?([\w\[\]]+,{1}\s*?)*?(\s*?author:).*("|')(.*)}}/g, // eslint-disable-line no-useless-escape helper: 'filter="author:[...]"' }, 'GS001-DEPR-AUTHBL': { level: 'error', rule: 'Replace {{#author}} with {{#primary_author}} or {{#foreach authors}}...{{/foreach}}', details: oneLineTrim`The usage of {{#author}} block helper outside of author.hbs is deprecated and should be replaced with {{#primary_author}} or {{#foreach authors}}...{{/foreach}}.
Find more information about the {{authors}} helper here.`, regex: /{{\s*?#author\s*?}}/g, notValidIn: 'author.hbs', helper: '{{#author}}' }, 'GS001-DEPR-CON-AUTH': { level: 'error', rule: `Replace {{#if author.*}} with {{#if primary_author.*}} or {{#if authors.[#].*}}`, details: oneLineTrim`The usage of {{#if author.*}} is deprecated and should be replaced with {{#if primary_author.*}} or {{#if authors.[#].*}}.
Find more information about the {{authors}} helper here.`, regex: /{{\s*?#if\s*?(author)(?:\.\w+)*?\s*?}}/g, helper: '{{#if author.*}}' }, 'GS001-DEPR-CON-PAUTH': { level: 'error', rule: `Replace {{#if post.author.*}} with {{#if post.primary_author.*}} or {{#if post.authors.[#].*}}`, details: oneLineTrim`The usage of {{#if post.author.*}} is deprecated and should be replaced with {{#if post.primary_author.*}} or {{#if post.authors.[#].*}}.
Find more information about the {{authors}} helper here.`, regex: /{{\s*?#if\s*?(?:post\.)(author)(?:\.\w+)*?\s*?}}/g, helper: '{{#if post.author.*}}' }, 'GS001-DEPR-AUTH': { level: 'error', rule: 'Replace {{author}} with {{authors}}', details: oneLineTrim`The usage of {{author}} is deprecated and should be replaced with {{authors}}.
Find more information about the {{authors}} helper here.`, regex: /{{\s*?author\s*?}}/g, helper: '{{author}}' }, 'GS001-DEPR-AUTH-ID': { level: 'error', rule: 'Replace {{author.id}} with {{primary_author.id}} or {{authors.[#].id}}', details: oneLineTrim`The usage of {{author.id}} is deprecated and should be replaced with either {{primary_author.id}} or {{authors.[#].id}}.
Find more information about the {{authors}} helper here.`, regex: /{{\s*?author\.id\s*?}}/g, helper: '{{author.id}}' }, 'GS001-DEPR-AUTH-SLUG': { level: 'error', rule: 'Replace {{author.slug}} with {{primary_author.slug}} or {{authors.[#].slug}}', details: oneLineTrim`The usage of {{author.slug}} is deprecated and should be replaced with either {{primary_author.slug}} or {{authors.[#].slug}}.
Find more information about the {{authors}} helper here.`, regex: /{{\s*?author\.slug\s*?}}/g, helper: '{{author.slug}}' }, 'GS001-DEPR-AUTH-MAIL': { level: 'error', rule: 'Replace {{author.email}} with {{primary_author.email}} or {{authors.[#].email}}', details: oneLineTrim`The usage of {{author.email}} is deprecated and should be replaced with either {{primary_author.email}} or {{authors.[#].email}}.
Find more information about the {{authors}} helper here.`, regex: /{{\s*?author\.email\s*?}}/g, helper: '{{author.email}}' }, 'GS001-DEPR-AUTH-MT': { level: 'error', rule: 'Replace {{author.meta_title}} with {{primary_author.meta_title}} or {{authors.[#].meta_title}}', details: oneLineTrim`The usage of {{author.meta_title}} is deprecated and should be replaced with either {{primary_author.meta_title}} or {{authors.[#].meta_title}}.
Find more information about the {{authors}} helper here.`, regex: /{{\s*?author\.meta_title\s*?}}/g, helper: '{{author.meta_title}}' }, 'GS001-DEPR-AUTH-MD': { level: 'error', rule: 'Replace {{author.meta_description}} with {{primary_author.meta_description}} or {{authors.[#].meta_description}}', details: oneLineTrim`The usage of {{author.meta_description}} is deprecated and should be replaced with either {{primary_author.meta_description}} or {{authors.[#].meta_description}}.
Find more information about the {{authors}} helper here.`, regex: /{{\s*?author\.meta_description\s*?}}/g, helper: '{{author.meta_description}}' }, 'GS001-DEPR-AUTH-NAME': { level: 'error', rule: 'Replace {{author.name}} with {{primary_author.name}} or {{authors.[#].name}}', details: oneLineTrim`The usage of {{author.name}} is deprecated and should be replaced with either {{primary_author.name}} or {{authors.[#].name}}.
Find more information about the {{authors}} helper here.`, regex: /{{\s*?author\.name\s*?}}/g, helper: '{{author.name}}' }, 'GS001-DEPR-AUTH-BIO': { level: 'error', rule: 'Replace {{author.bio}} with {{primary_author.bio}} or {{authors.[#].bio}}', details: oneLineTrim`The usage of {{author.bio}} is deprecated and should be replaced with either {{primary_author.bio}} or {{authors.[#].bio}}.
Find more information about the {{authors}} helper here.`, regex: /{{\s*?author\.bio\s*?}}/g, helper: '{{author.bio}}' }, 'GS001-DEPR-AUTH-LOC': { level: 'error', rule: 'Replace {{author.location}} with {{primary_author.location}} or {{authors.[#].location}}', details: oneLineTrim`The usage of {{author.location}} is deprecated and should be replaced with either {{primary_author.location}} or {{authors.[#].location}}.
Find more information about the {{authors}} helper here.`, regex: /{{\s*?author\.location\s*?}}/g, helper: '{{author.location}}' }, 'GS001-DEPR-AUTH-WEB': { level: 'error', rule: 'Replace {{author.website}} with {{primary_author.website}} or {{authors.[#].website}}', details: oneLineTrim`The usage of {{author.website}} is deprecated and should be replaced with either {{primary_author.website}} or {{authors.[#].website}}.
Find more information about the {{authors}} helper here.`, regex: /{{\s*?author\.website\s*?}}/g, helper: '{{author.website}}' }, 'GS001-DEPR-AUTH-TW': { level: 'error', rule: 'Replace {{author.twitter}} with {{primary_author.twitter}} or {{authors.[#].twitter}}', details: oneLineTrim`The usage of {{author.twitter}} is deprecated and should be replaced with either {{primary_author.twitter}} or {{authors.[#].twitter}}.
Find more information about the {{authors}} helper here.`, regex: /{{\s*?author\.twitter\s*?}}/g, helper: '{{author.twitter}}' }, 'GS001-DEPR-AUTH-FB': { level: 'error', rule: 'Replace {{author.facebook}} with {{primary_author.facebook}} or {{authors.[#].facebook}}', details: oneLineTrim`The usage of {{author.facebook}} is deprecated and should be replaced with either {{primary_author.facebook}} or {{authors.[#].facebook}}.
Find more information about the {{authors}} helper here.`, regex: /{{\s*?author\.facebook\s*?}}/g, helper: '{{author.facebook}}' }, 'GS001-DEPR-AUTH-PIMG': { level: 'error', rule: 'Replace {{author.profile_image}} with {{primary_author.profile_image}} or {{authors.[#].profile_image}}', details: oneLineTrim`The usage of {{author.profile_image}} is deprecated and should be replaced with either {{primary_author.profile_image}} or {{authors.[#].profile_image}}.
Find more information about the {{authors}} helper here.`, regex: /{{\s*?author\.profile_image\s*?}}/g, helper: '{{author.profile_image}}' }, 'GS001-DEPR-AUTH-CIMG': { level: 'error', rule: 'Replace {{author.cover_image}} with {{primary_author.cover_image}} or {{authors.[#].cover_image}}', details: oneLineTrim`The usage of {{author.cover_image}} is deprecated and should be replaced with either {{primary_author.cover_image}} or {{authors.[#].cover_image}}.
Find more information about the {{authors}} helper here.`, regex: /{{\s*?author\.cover_image\s*?}}/g, helper: '{{author.cover_image}}' }, 'GS001-DEPR-AUTH-URL': { level: 'error', rule: 'Replace {{author.url}} with {{primary_author.url}} or {{authors.[#].url}}', details: oneLineTrim`The usage of {{author.url}} is deprecated and should be replaced with either {{primary_author.url}} or {{authors.[#].url}}.
Find more information about the {{authors}} helper here.`, regex: /{{\s*?author\.url\s*?}}/g, helper: '{{author.url}}' }, 'GS001-DEPR-PAUTH': { level: 'error', rule: 'Replace {{post.author}} with {{post.primary_author}} or {{authors.[#]}}', details: oneLineTrim`The usage of {{post.author}} is deprecated and should be replaced with either {{post.primary_author}} or {{post.authors.[#]}}.
Find more information about the {{authors}} helper here.`, regex: /{{\s*?post\.author\s*?}}/g, helper: '{{post.author}}' }, 'GS001-DEPR-PAUTH-ID': { level: 'error', rule: 'Replace {{post.author.id}} with {{post.primary_author.id}} or {{authors.[#].id}}', details: oneLineTrim`The usage of {{post.author.id}} is deprecated and should be replaced with either {{post.primary_author.id}} or {{post.authors.[#].id}}.
Find more information about the {{authors}} helper here.`, regex: /{{\s*?post\.author\.id\s*?}}/g, helper: '{{post.author.id}}' }, 'GS001-DEPR-PAUTH-SLUG': { level: 'error', rule: 'Replace {{post.author.slug}} with {{post.primary_author.slug}} or {{post.authors.[#].slug}}', details: oneLineTrim`The usage of {{post.author.slug}} is deprecated and should be replaced with either {{post.primary_author.slug}} or {{post.authors.[#].slug}}.
Find more information about the {{authors}} helper here.`, regex: /{{\s*?post\.author\.slug\s*?}}/g, helper: '{{post.author.slug}}' }, 'GS001-DEPR-PAUTH-MAIL': { level: 'error', rule: 'Replace {{post.author.email}} with {{post.primary_author.email}} or {{post.authors.[#].email}}', details: oneLineTrim`The usage of {{post.author.email}} is deprecated and should be replaced with either {{post.primary_author.email}} or {{post.authors.[#].email}}.
Find more information about the {{authors}} helper here.`, regex: /{{\s*?post\.author\.email\s*?}}/g, helper: '{{post.author.email}}' }, 'GS001-DEPR-PAUTH-MT': { level: 'error', rule: 'Replace {{post.author.meta_title}} with {{post.primary_author.meta_title}} or {{post.authors.[#].meta_title}}', details: oneLineTrim`The usage of {{post.author.meta_title}} is deprecated and should be replaced with either {{post.primary_author.meta_title}} or {{post.authors.[#].meta_title}}.
Find more information about the {{authors}} helper here.`, regex: /{{\s*?post\.author\.meta_title\s*?}}/g, helper: '{{post.author.meta_title}}' }, 'GS001-DEPR-PAUTH-MD': { level: 'error', rule: 'Replace {{post.author.meta_description}} with {{post.primary_author.meta_description}} or {{post.authors.[#].meta_description}}', details: oneLineTrim`The usage of {{post.author.meta_description}} is deprecated and should be replaced with either {{post.primary_author.meta_description}} or {{post.authors.[#].meta_description}}.
Find more information about the {{authors}} helper here.`, regex: /{{\s*?post\.author\.meta_description\s*?}}/g, helper: '{{post.author.meta_description}}' }, 'GS001-DEPR-PAUTH-NAME': { level: 'error', rule: 'Replace {{post.author.name}} with {{post.primary_author.name}} or {{post.authors.[#].name}}', details: oneLineTrim`The usage of {{post.author.name}} is deprecated and should be replaced with either {{post.primary_author.name}} or {{post.authors.[#].name}}.
Find more information about the {{authors}} helper here.`, regex: /{{\s*?post\.author\.name\s*?}}/g, helper: '{{post.author.name}}' }, 'GS001-DEPR-PAUTH-BIO': { level: 'error', rule: 'Replace {{post.author.bio}} with {{post.primary_author.bio}} or {{post.authors.[#].bio}}', details: oneLineTrim`The usage of {{post.author.bio}} is deprecated and should be replaced with either {{post.primary_author.bio}} or {{post.authors.[#].bio}}.
Find more information about the {{authors}} helper here.`, regex: /{{\s*?post\.author\.bio\s*?}}/g, helper: '{{post.author.bio}}' }, 'GS001-DEPR-PAUTH-LOC': { level: 'error', rule: 'Replace {{post.author.location}} with {{post.primary_author.location}} or {{post.authors.[#].location}}', details: oneLineTrim`The usage of {{post.author.location}} is deprecated and should be replaced with either {{post.primary_author.location}} or {{post.authors.[#].location}}.
Find more information about the {{authors}} helper here.`, regex: /{{\s*?post\.author\.location\s*?}}/g, helper: '{{post.author.location}}' }, 'GS001-DEPR-PAUTH-WEB': { level: 'error', rule: 'Replace {{post.author.website}} with {{post.primary_author.website}} or {{post.authors.[#].website}}', details: oneLineTrim`The usage of {{post.author.website}} is deprecated and should be replaced with either {{post.primary_author.website}} or {{post.authors.[#].website}}.
Find more information about the {{authors}} helper here.`, regex: /{{\s*?post\.author\.website\s*?}}/g, helper: '{{post.author.website}}' }, 'GS001-DEPR-PAUTH-TW': { level: 'error', rule: 'Replace {{post.author.twitter}} with {{post.primary_author.twitter}} or {{post.authors.[#].twitter}}', details: oneLineTrim`The usage of {{post.author.twitter}} is deprecated and should be replaced with either {{post.primary_author.twitter}} or {{post.authors.[#].twitter}}.
Find more information about the {{authors}} helper here.`, regex: /{{\s*?post\.author\.twitter\s*?}}/g, helper: '{{post.author.twitter}}' }, 'GS001-DEPR-PAUTH-FB': { level: 'error', rule: 'Replace {{post.author.facebook}} with {{post.primary_author.facebook}} or {{post.authors.[#].facebook}}', details: oneLineTrim`The usage of {{post.author.facebook}} is deprecated and should be replaced with either {{post.primary_author.facebook}} or {{post.authors.[#].facebook}}.
Find more information about the {{authors}} helper here.`, regex: /{{\s*?post\.author\.facebook\s*?}}/g, helper: '{{post.author.facebook}}' }, 'GS001-DEPR-PAUTH-PIMG': { level: 'error', rule: 'Replace {{post.author.profile_image}} with {{post.primary_author.profile_image}} or {{post.authors.[#].profile_image}}', details: oneLineTrim`The usage of {{post.author.profile_image}} is deprecated and should be replaced with either {{post.primary_author.profile_image}} or {{post.authors.[#].profile_image}}.
Find more information about the {{authors}} helper here.`, regex: /{{\s*?post\.author\.profile_image\s*?}}/g, helper: '{{post.author.profile_image}}' }, 'GS001-DEPR-PAUTH-CIMG': { level: 'error', rule: 'Replace {{post.author.cover_image}} with {{post.primary_author.cover_image}} or {{post.authors.[#].cover_image}}', details: oneLineTrim`The usage of {{post.author.cover_image}} is deprecated and should be replaced with either {{post.primary_author.cover_image}} or {{post.authors.[#].cover_image}}.
Find more information about the {{authors}} helper here.`, regex: /{{\s*?post\.author\.cover_image\s*?}}/g, helper: '{{post.author.cover_image}}' }, 'GS001-DEPR-PAUTH-URL': { level: 'error', rule: 'Replace {{post.author.url}} with {{post.primary_author.url}} or {{post.authors.[#].url}}', details: oneLineTrim`The usage of {{post.author.url}} is deprecated and should be replaced with either {{post.primary_author.url}} or {{post.authors.[#].url}}.
Find more information about the {{authors}} helper here.`, regex: /{{\s*?post\.author\.url\s*?}}/g, helper: '{{post.author.url}}' }, 'GS001-DEPR-PAID': { level: 'error', rule: 'Replace {{post.author_id}} code with {{post.primary_author.id}}', details: oneLineTrim`The {{post.author_id}} attribute in post context was removed
Instead of {{post.author_id}} you need to use {{post.primary_author.id}}.
See the object attributes of post here.`, regex: /{{\s*?post\.author_id\s*?}}/g, helper: '{{post.author_id}}' }, 'GS001-DEPR-NAUTH': { level: 'error', rule: 'Replace ../author with ../primary_author or ../authors.[#]', details: oneLineTrim`The usage of ../author is deprecated and should be replaced with either ../primary_author or ../authors.[#].
Find more information about the {{authors}} helper here.`, regex: /{{\s*?(?:#|#if)?\s*?\.\.\/author(?:\.\S*?)?\s*?}}/g, helper: '{{../author}}' }, 'GS001-DEPR-IUA': { level: 'error', rule: 'Replace {{img_url author.*}} with {{img_url primary_author.*}} or .{img_url author.[#].*}}', details: oneLineTrim`The usage of {{img_url author.*}} is deprecated and should be replaced with either {{img_url primary_author.*}} or {{img_url author.[#].*}}.
Find more information about the {{authors}} helper here.`, regex: /{{\s*?img_url\s*?(author.).*}}/g, helper: '{{img_url author.*}}' }, 'GS001-DEPR-BLOG': { level: 'error', rule: 'The {{@blog}} helper should be replaced with {{@site}}', details: oneLineTrim`With the introduction of the Content API {{@blog}} became deprecated in favour of {{@site}}.
The {{@blog}} helper will be removed in next version of Ghost and should not be used. Find more information about the @site property here.`, regex: /{{\s*?@blog\.[a-zA-Z0-9_]+\s*?}}/g, helper: '{{@blog}}' }, 'GS001-DEPR-BPL': { level: 'error', rule: '{{@blog.permalinks}} was removed', details: oneLineTrim`With the introduction of Dynamic Routing, you can define multiple permalinks.
The {{@blog.permalinks}} property will therefore no longer be used and should be removed from the theme. Find more information about Ghost data helpers here.`, regex: /{{\s*?@blog\.permalinks\s*?}}/g, helper: '{{@blog.permalinks}}' }, 'GS001-DEPR-SPL': { level: 'error', rule: '{{@site.permalinks}} was removed', details: oneLineTrim`With the introduction of Dynamic Routing, you can define multiple permalinks.
The {{@site.permalinks}} property will therefore no longer be used and should be removed from the theme. Find more information about the @site property here.`, regex: /{{\s*?@site\.permalinks\s*?}}/g, helper: '{{@site.permalinks}}' }, 'GS001-DEPR-SGH': { level: 'error', rule: 'Replace {{@site.ghost_head}} with {{ghost_head}}', details: oneLineTrim`The usage of {{@site.ghost_head}} is deprecated and should be replaced with {{ghost_head}}.
The {{@site.ghost_head}} property will therefore no longer be used and should be removed from the theme. Find more information about the {{ghost_head}} property here.`, regex: /{{\s*?@site\.ghost_head\s*?}}/g, helper: '{{@site.ghost_head}}' }, 'GS001-DEPR-SGF': { level: 'error', rule: 'Replace {{@site.ghost_foot}} with {{ghost_foot}}', details: oneLineTrim`The usage of {{@site.ghost_foot}} is deprecated and should be replaced with {{ghost_foot}}.
The {{@site.ghost_foot}} property will therefore no longer be used and should be removed from the theme. Find more information about the {{ghost_foot}} property here.`, regex: /{{\s*?@site\.ghost_foot\s*?}}/g, helper: '{{@site.ghost_foot}}' }, 'GS001-DEPR-LANG': { level: 'error', rule: 'The {{lang}} helper should be replaced with {{@site.lang}}', details: oneLineTrim`The {{lang}} helper is a duplicate of {{@site.lang}}. Using {{@site.lang}} is preferred.
The {{lang}} helper will be removed in next version of Ghost and should not be used. Find more information about the @site.lang property here.`, regex: /{{\s*?lang\s*?}}/g, helper: '{{lang}}' }, 'GS001-DEPR-CSS-KGMD': { level: 'warning', rule: `.kg-card-markdown doesn't exist in current version of Ghost, ensure your theme works without it`, details: oneLineTrim`The .kg-card-markdown CSS class is deprecated and will no longer be used in Ghost. It's recommended to add your own wrapper around the {{content}} helper and target that instead if needed. Find out more about required theme changes for the Koenig editor here.`, regex: /\.kg-card-markdown/g, className: '.kg-card-markdown', css: true }, 'GS050-CSS-KGWW': { level: 'error', rule: requiredClassRule`kg-width-wide`, details: requiredClassDetails`kg-width-wide`, regex: /\.kg-width-wide/g, className: '.kg-width-wide', css: true }, 'GS050-CSS-KGWF': { level: 'error', rule: requiredClassRule`kg-width-full`, details: requiredClassDetails`kg-width-full`, regex: /\.kg-width-full/g, className: '.kg-width-full', css: true }, 'GS050-CSS-KGGC': { level: 'error', rule: requiredClassRule`kg-gallery-container`, details: requiredClassDetails``, regex: /\.kg-gallery-container/g, className: '.kg-gallery-container', css: true, cardAsset: 'gallery' }, 'GS050-CSS-KGGR': { level: 'error', rule: requiredClassRule`kg-gallery-row`, details: requiredClassDetails`kg-gallery-row`, regex: /\.kg-gallery-row/g, className: '.kg-gallery-row', css: true, cardAsset: 'gallery' }, 'GS050-CSS-KGGI': { level: 'error', rule: requiredClassRule`kg-gallery-image`, details: requiredClassDetails`kg-gallery-image`, regex: /\.kg-gallery-image/g, className: '.kg-gallery-image', css: true, cardAsset: 'gallery' }, 'GS050-CSS-KGBM': { level: 'error', rule: requiredClassRule`kg-bookmark-card`, details: requiredClassDetails`kg-bookmark-card`, regex: /\.kg-bookmark-card/g, className: '.kg-bookmark-card', css: true, cardAsset: 'bookmark' }, 'GS050-CSS-KGBMCO': { level: 'error', rule: requiredClassRule`kg-bookmark-container`, details: requiredClassDetails`kg-bookmark-container`, regex: /\.kg-bookmark-container/g, className: '.kg-bookmark-container', css: true, cardAsset: 'bookmark' }, 'GS050-CSS-KGBMCON': { level: 'error', rule: requiredClassRule`kg-bookmark-content`, details: requiredClassDetails`kg-bookmark-content`, regex: /\.kg-bookmark-content/g, className: '.kg-bookmark-content', css: true, cardAsset: 'bookmark' }, 'GS050-CSS-KGBMTI': { level: 'error', rule: requiredClassRule`kg-bookmark-title`, details: requiredClassDetails`kg-bookmark-title`, regex: /\.kg-bookmark-title/g, className: '.kg-bookmark-title', css: true, cardAsset: 'bookmark' }, 'GS050-CSS-KGBMDE': { level: 'error', rule: requiredClassRule`kg-bookmark-description`, details: requiredClassDetails`kg-bookmark-description`, regex: /\.kg-bookmark-description/g, className: '.kg-bookmark-description', css: true, cardAsset: 'bookmark' }, 'GS050-CSS-KGBMME': { level: 'error', rule: requiredClassRule`kg-bookmark-metadata`, details: requiredClassDetails`kg-bookmark-metadata`, regex: /\.kg-bookmark-metadata/g, className: '.kg-bookmark-metadata', css: true, cardAsset: 'bookmark' }, 'GS050-CSS-KGBMIC': { level: 'error', rule: requiredClassRule`kg-bookmark-icon`, details: requiredClassDetails`kg-bookmark-icon`, regex: /\.kg-bookmark-icon/g, className: '.kg-bookmark-icon', css: true, cardAsset: 'bookmark' }, 'GS050-CSS-KGBMAU': { level: 'error', rule: requiredClassRule`kg-bookmark-author`, details: requiredClassDetails`kg-bookmark-author`, regex: /\.kg-bookmark-author/g, className: '.kg-bookmark-author', css: true, cardAsset: 'bookmark' }, 'GS050-CSS-KGBMPU': { level: 'error', rule: requiredClassRule`kg-bookmark-publisher`, details: requiredClassDetails``, regex: /\.kg-bookmark-publisher/g, className: '.kg-bookmark-publisher', css: true, cardAsset: 'bookmark' }, 'GS050-CSS-KGBMTH': { level: 'error', rule: requiredClassRule`kg-bookmark-thumbnail`, details: requiredClassDetails``, regex: /\.kg-bookmark-thumbnail/g, className: '.kg-bookmark-thumbnail', css: true, cardAsset: 'bookmark' }, // Updated v1 rules 'GS001-DEPR-AC': { level: 'error', rule: 'Replace {{author.cover}} with {{primary_author.cover_image}}', details: oneLineTrim`The cover attribute was replaced with cover_image.
Instead of {{author.cover}} you need to use {{primary_author.cover_image}} or {{authors.[#].cover_image}}.
See the object attributes of author here.`, regex: /{{\s*?author\.cover\s*?}}/g, helper: '{{author.cover}}' }, 'GS001-DEPR-AC-2': { level: 'error', rule: 'Replace {{primary_author.cover}} with {{primary_author.cover_image}}', details: oneLineTrim`The cover attribute was replaced with cover_image.
Instead of {{primary_author.cover}} you need to use {{primary_author.cover_image}}.
See the object attributes of author here.`, regex: /{{\s*?primary_author\.cover\s*?}}/g, helper: '{{primary_author.cover}}' }, 'GS001-DEPR-AC-3': { level: 'error', rule: 'Replace {{authors.[#].cover}} with {{authors.[#].cover_image}}', details: oneLineTrim`The cover attribute was replaced with cover_image.
Instead of {{authors.[#].cover}} you need to use {{authors.[#].cover_image}}.
See the object attributes of author here.`, regex: /{{\s*?authors\.\[[0-9]+\]\.(cover)\s*?}}/g, helper: '{{authors.[#].cover}}' }, 'GS001-DEPR-AIMG': { level: 'error', rule: 'Replace {{author.image}} with {{primary_author.profile_image}} or {{authors.[#].profile_image}}', details: oneLineTrim`The image attribute was replaced with profile_image.
Instead of {{author.image}}, you need to use {{primary_author.profile_image}} or {{authors.[#].profile_image}}.
See the object attributes of author here.`, regex: /{{\s*?author\.image\s*?}}/g, helper: '{{author.image}}' }, 'GS001-DEPR-AIMG-2': { level: 'error', rule: 'Replace {{primary_author.image}} with {{primary_author.profile_image}}', details: oneLineTrim`The image attribute was replaced with profile_image.
Instead of {{primary_author.image}}, you need to use {{primary_author.profile_image}}.
See the object attributes of author here.`, regex: /{{\s*?primary_author\.(image)\s*?}}/g, helper: '{{primary_author.image}}' }, 'GS001-DEPR-AIMG-3': { level: 'error', rule: 'Replace {{authors.[#].image}} with {{authors.[#].profile_image}}', details: oneLineTrim`The image attribute was replaced with profile_image.
Instead of {{authors.[#].image}}, you need to use {{authors.[#].profile_image}}.
See the object attributes of author here.`, regex: /{{\s*?authors\.\[[0-9]+\]\.(cover)\s*?}}/g, helper: '{{authors.[#].image}}' }, 'GS001-DEPR-PAC': { level: 'error', rule: 'Replace {{post.author.cover}} with {{post.primary_author.cover_image}} or {{post.authors.[#].cover_image}}', details: oneLineTrim`The cover attribute was replaced with cover_image.
Instead of {{post.author.cover}}, you need to use {{post.primary_author.cover_image}} or {{post.authors.[#].cover_image}}.
See the object attributes of author here.`, regex: /{{\s*?post\.author\.cover\s*?}}/g, helper: '{{post.author.cover}}' }, 'GS001-DEPR-PAC-2': { level: 'error', rule: 'Replace {{post.primary_author.cover}} with {{post.primary_author.cover_image}}', details: oneLineTrim`The cover attribute was replaced with cover_image.
Instead of {{post.primary_author.cover}}, you need to use {{post.primary_author.cover_image}}.
See the object attributes of author here.`, regex: /{{\s*?post\.primary_author\.cover\s*?}}/g, helper: '{{post.primary_author.cover}}' }, 'GS001-DEPR-PAC-3': { level: 'error', rule: 'Replace {{post.authors.[#].cover}} with {{post.authors.[#].cover_image}}', details: oneLineTrim`The cover attribute was replaced with cover_image.
Instead of {{post.authors.[#].cover}}, you need to use {{post.authors.[#].cover_image}}.
See the object attributes of author here.`, regex: /{{\s*?post\.authors\.\[[0-9]+\]\.(cover)\s*?}}/g, helper: '{{post.authors.[#].cover}}' }, 'GS001-DEPR-PAIMG': { level: 'error', rule: 'Replace {{post.author.image}} with {{post.primary_author.profile_image}} or {{post.authors.[#].profile_image}}', details: oneLineTrim`The image attribute was replaced with profile_image.
Instead of {{post.author.image}}, you need to use {{post.primary_author.profile_image}} or {{post.authors.[#].profile_image}}.
See the object attributes of author here.`, regex: /{{\s*?post\.author\.image\s*?}}/g, helper: '{{post.author.image}}' }, 'GS001-DEPR-PAIMG-2': { level: 'error', rule: 'Replace {{post.primary_author.image}} with {{post.primary_author.profile_image}}', details: oneLineTrim`The image attribute was replaced with profile_image.
Instead of {{post.primary_author.image}}, you need to use {{post.primary_author.profile_image}}.
See the object attributes of author here.`, regex: /{{\s*?post\.primary_author\.image\s*?}}/g, helper: '{{post.primary_author.image}}' }, 'GS001-DEPR-PAIMG-3': { level: 'error', rule: 'Replace {{post.authors.[#].image}} with {{post.authors.[#].profile_image}}', details: oneLineTrim`The image attribute was replaced with profile_image.
Instead of {{post.authors.[#].image}}, you need to use {{post.authors.[#].profile_image}}.
See the object attributes of author here.`, regex: /{{\s*?post\.authors\.\[[0-9]+\]\.(image)\s*?}}/g, helper: '{{post.authors.[#].image}}' }, 'GS001-DEPR-CON-AC': { level: 'error', rule: 'Replace {{#if author.cover}} with {{#if primary_author.cover_image}} or {{#if authors.[#].cover_image}}', details: oneLineTrim`The cover attribute was replaced with cover_image.
Instead of {{#if author.cover}}, you need to use {{#if primary_author.cover_image}} or {{#if authors.[#].cover_image}}.
See the object attributes of author here.`, regex: /{{\s*?#if\s*?author\.cover\s*?}}/g, helper: '{{#if author.cover}}' }, 'GS001-DEPR-CON-AC-2': { level: 'error', rule: 'Replace {{#if primary_author.cover}} with {{#if primary_author.cover_image}}', details: oneLineTrim`The cover attribute was replaced with cover_image.
Instead of {{#if primary_author.cover}}, you need to use {{#if primary_author.cover_image}}.
See the object attributes of author here.`, regex: /{{\s*?#if\s*?primary_author\.cover\s*?}}/g, helper: '{{#if primary_author.cover}}' }, 'GS001-DEPR-CON-AC-3': { level: 'error', rule: 'Replace {{#if authors.[#].cover}} with {{#if authors.[#].cover_image}}', details: oneLineTrim`The cover attribute was replaced with cover_image.
Instead of {{#if authors.[#].cover}}, you need to use {{#if authors.[#].cover_image}}.
See the object attributes of author here.`, regex: /{{\s*?#if\s*?authors\.\[[0-9]+\]\.cover\s*?}}/g, helper: '{{#if authors.[#].cover}}' }, 'GS001-DEPR-CON-AIMG': { level: 'error', rule: 'Replace {{#if author.image}} with {{#if primary_author.profile_image}} or {{#if authors.[#].profile_image}}', details: oneLineTrim`The image attribute was replaced with profile_image.
Instead of {{#if author.image}}, you need to use {{#if primary_author.profile_image}} or {{#if authors.[#].profile_image}}.
See the object attributes of author here.`, regex: /{{\s*?#if\s*?author\.image\s*?}}/g, helper: '{{#if author.image}}' }, 'GS001-DEPR-CON-AIMG-2': { level: 'error', rule: 'Replace {{#if primary_author.image}} with {{#if primary_author.profile_image}}', details: oneLineTrim`The image attribute was replaced with profile_image.
Instead of {{#if primary_author.image}}, you need to use {{#if primary_author.profile_image}}.
See the object attributes of author here.`, regex: /{{\s*?#if\s*?primary_author\.image\s*?}}/g, helper: '{{#if primary_author.image}}' }, 'GS001-DEPR-CON-AIMG-3': { level: 'error', rule: 'Replace {{#if authors.[#].image}} with {{#if authors.[#].profile_image}}', details: oneLineTrim`The image attribute was replaced with profile_image.
Instead of {{#if authors.[#].image}}, you need to use {{#if authors.[#].profile_image}}.
See the object attributes of author here.`, regex: /{{\s*?#if\s*?authors\.\[[0-9]+\]\.image\s*?}}/g, helper: '{{#if authors.[#].image}}' }, 'GS001-DEPR-CON-PAC': { level: 'error', rule: 'Replace {{#if post.author.cover}} with {{#if post.primary_author.cover_image}} or {{#if post.authors.[#].cover_image}}', details: oneLineTrim`The cover attribute was replaced with cover_image.
Instead of {{#if post.author.cover}}, you need to use {{#if post.primary_author.cover_image}} or {{#if post.authors.[#].cover_image}}.
See the object attributes of author here.`, regex: /{{\s*?#if\s*?post\.author\.cover\s*?}}/g, helper: '{{#if post.author.cover}}' }, 'GS001-DEPR-CON-PAC-2': { level: 'error', rule: 'Replace {{#if post.primary_author.cover}} with {{#if post.primary_author.cover_image}}', details: oneLineTrim`The cover attribute was replaced with cover_image.
Instead of {{#if post.primary_author.cover}}, you need to use {{#if post.primary_author.cover_image}}.
See the object attributes of author here.`, regex: /{{\s*?#if\s*?post\.primary_author\.cover\s*?}}/g, helper: '{{#if post.primary_author.cover}}' }, 'GS001-DEPR-CON-PAC-3': { level: 'error', rule: 'Replace {{#if post.authors.[#].cover}} with {{#if post.authors.[#].cover_image}}', details: oneLineTrim`The cover attribute was replaced with cover_image.
Instead of {{#if post.authors.[#].cover}}, you need to use {{#if post.authors.[#].cover_image}}.
See the object attributes of author here.`, regex: /{{\s*?#if\s*?post\.authors\.\[[0-9]+\]\.cover\s*?}}/g, helper: '{{#if post.authors.[#].cover}}' }, 'GS001-DEPR-CON-PAIMG': { level: 'error', rule: 'Replace {{#if post.author.image}} with {{#if post.primary_author.profile_image}} or {{#if post.authors.[#].profile_image}}', details: oneLineTrim`The image attribute was replaced with profile_image.
Instead of {{#if post.author.image}}, you need to use {{#if post.primary_author.profile_image}} or {{#if post.authors.[#].profile_image}}.
See the object attributes of author here.`, regex: /{{\s*?#if\s*?post\.author\.image\s*?}}/g, helper: '{{#if post.author.image}}' }, 'GS001-DEPR-CON-PAIMG-2': { level: 'error', rule: 'Replace {{#if post.primary_author.image}} with {{#if post.primary_author.profile_image}}', details: oneLineTrim`The image attribute was replaced with profile_image.
Instead of {{#if post.primary_author.image}}, you need to use {{#if post.primary_author.profile_image}}.
See the object attributes of author here.`, regex: /{{\s*?#if\s*?post\.primary_author\.image\s*?}}/g, helper: '{{#if post.primary_author.image}}' }, 'GS001-DEPR-CON-PAIMG-3': { level: 'error', rule: 'Replace {{#if post.authors.[#].image}} with {{#if post.authors.[#].profile_image}}', details: oneLineTrim`The image attribute was replaced with profile_image.
Instead of {{#if post.authors.[#].image}}, you need to use {{#if post.authors.[#].profile_image}}.
See the object attributes of author here.`, regex: /{{\s*?#if\s*?post\.authors\.\[[0-9]+\]\.image\s*?}}/g, helper: '{{#if post.authors.[#].image}}' }, 'GS010-PJ-KEYWORDS': { level: 'warning', rule: 'package.json property keywords should contain ghost-theme', details: oneLineTrim`The property keywords in your package.json file must contain ghost-theme. E.g. {"keywords": ["ghost-theme"]}.
Check the package.json documentation for further information.` } }; knownHelpers = _.union(previousKnownHelpers, knownHelpers); templates = _.union(previousTemplates, templates); // Merge the previous rules into the new rules, but overwrite any specified property, // as well as adding any new rule to the spec. // Furthermore, replace the usage of the old doc URLs that we're linking to, with the // new version. rules = _.each(_.merge({}, previousRules, rules), function replaceDocsUrl(value) { value.details = value.details.replace(prevDocsBaseUrlRegEx, docsBaseUrl); }); module.exports = { knownHelpers: knownHelpers, templates: templates, rules: rules, /** * Copy of Ghost defaults for https://github.com/TryGhost/Ghost/blob/e25f1df0ae551c447da0d319bae06eadf9665444/core/frontend/services/theme-engine/config/defaults.json */ defaultPackageJSON: { posts_per_page: 5, card_assets: { exclude: ['bookmark', 'gallery'] } } };