const _ = require('lodash'); const oneLineTrim = require('common-tags/lib/oneLineTrim'); const previousSpec = require('./v4'); const ghostVersions = require('../utils').versions; const docsBaseUrl = `https://ghost.org/docs/themes/`; const prevDocsBaseUrl = `https://themes.ghost.org/v${ghostVersions.v5.docs}/docs/`; const prevDocsBaseUrlRegEx = new RegExp(prevDocsBaseUrl, 'g'); const previousKnownHelpers = previousSpec.knownHelpers; const previousTemplates = previousSpec.templates; const previousRules = _.cloneDeep(previousSpec.rules); const multiAuthorDesc = `Ghost allows multiple authors to be assigned to a post, so all helpers have been reworked to account for this.`; const authorHelperDocs = `Find more information about the {{authors}} helper here`; const tierDesc = `Ghost now supports multiple tiers and subscriptions. All product and price related helpers have been reworked to account for this.`; // assign new or overwrite existing knownHelpers, templates, or rules here: let knownHelpers = ['total_members', 'total_paid_members', 'comment_count', 'comments', 'recommendations', 'readable_url']; let templates = []; let rules = { // New rules 'GS010-PJ-GHOST-API-PRESENT': { level: 'warning', rule: 'Remove "engines.ghost-api" from package.json', details: oneLineTrim`The "ghost-api" version is no longer used and can be removed.
Find more information about the package.json file here.` }, 'GS010-PJ-GHOST-CARD-ASSETS-NOT-PRESENT': { level: 'warning', rule: '"card_assets" will now be included by default, including bookmark and gallery cards.', details: oneLineTrim`The "card_assets" property is enabled by default and set to true (include all) if not explicitly set.
Find more information about the card_assets property here.` }, 'GS090-NO-AUTHOR-HELPER-IN-POST-CONTEXT': { level: 'error', fatal: false, rule: 'Replace {{author}} with {{authors}}', details: oneLineTrim`The {{author}} helper was removed in favor of {{}}
${multiAuthorDesc}
${authorHelperDocs}`, helper: '{{author}}' }, 'GS090-NO-PRODUCTS-HELPER': { level: 'error', fatal: false, rule: 'Replace {{products}} with {{tiers}}', details: oneLineTrim`The {{products}} helper was removed in favor of {{tiers}}
${tierDesc}
Find more information about the {{tiers}} property here.`, helper: '{{products}}' }, 'GS090-NO-PRODUCT-DATA-HELPER': { level: 'error', fatal: false, rule: 'Replace {{@product}} with {{#get "tiers"}}', details: oneLineTrim`The {{@product}} data helper was removed in favor of {{#get "tiers"}}
${tierDesc}
Find more information about the {{#get "tiers"}} property here.`, helper: '{{@product}}' }, 'GS090-NO-PRODUCTS-DATA-HELPER': { level: 'error', fatal: false, rule: 'Replace {{@products}} with {{#get "tiers"}}', details: oneLineTrim`The {{@products}} data helper was removed in favor of {{#get "tiers"}}
${tierDesc}
Find more information about the {{#get "tiers"}} property here.`, helper: '{{@products}}' }, 'GS090-NO-MEMBER-PRODUCTS-DATA-HELPER': { level: 'error', rule: 'Replace {{@member.products}} with {{@member.subscriptions}}', details: oneLineTrim`The {{@member.products}} helper was removed in favor of {{@member.subscriptions}}
${tierDesc}
Find more information about the {{@member.subscriptions}} property here.`, helper: '{{@member.products}}' }, 'GS090-NO-PRICE-DATA-CURRENCY-GLOBAL': { level: 'error', fatal: false, rule: 'Replace {{@price.currency}} with {{#get "tiers"}} and {{currency}} or {{#foreach @member.subscriptions}} and {{plan.currency}}', details: oneLineTrim`There is no longer a global @price object. You need to use either {{#get "tiers"}} to fetch all tiers and use the {{currency}} property of a tier
or use {{#foreach @member.subscriptions}} to fetch an individual member's subscriptions, and use the {{plan.currency}} property from the subscription.
Find more information about the {{price}} helper here.` }, 'GS090-NO-PRICE-DATA-CURRENCY-CONTEXT': { level: 'error', fatal: false, rule: 'Replace {{@price.currency}} with {{currency}} or {{plan.currency}}', details: oneLineTrim`There is no longer a global @price object. Instead the {{currency}} property can be used inside {{#get "tiers"}}
or {{plan.currency}} can be used inside {{#foreach @member.subscriptions}}
Find more information about the {{price}} helper here.` }, 'GS090-NO-PRICE-DATA-MONTHLY-YEARLY': { level: 'error', fatal: false, rule: 'Replace {{@price.monthly}} and {{@price.yearly}} with {{price monthly_price currency=currency}} and {{price yearly_price currency=currency}} after fetching tier data with {{#get "tiers"}}', details: oneLineTrim`There is no longer a global @price object. You need to use {{#get "tiers"}} to fetch all the tiers and get access to the {{price monthly_price currency=currency}} or {{price yearly_price currency=currency}} for each tier
Find more information about the {{price}} helper here.` }, 'GS090-NO-TIER-PRICE-AS-OBJECT': { level: 'error', fatal: false, rule: 'Remove usage of {{monthly_price.*}} and {{yearly_price.*}}.', details: oneLineTrim`The usage of {{monthly_price.*}} and {{yearly_price.*}} is no longer supported.
${tierDesc}
Find more information about the {{#get "tiers"}} here.`, helper: '{{#get "tiers"}}' }, 'GS090-NO-TIER-BENEFIT-AS-OBJECT': { level: 'error', fatal: true, rule: 'Remove usage of {{name}} for tier benefits.', details: oneLineTrim`The usage of {{name}} for tier benefits is no longer supported.
${tierDesc}
Find more information about the {{#get "tiers"}} here.`, helper: '{{#get "tiers"}}' }, 'GS001-DEPR-AUTH-ID': { level: 'error', fatal: false, rule: 'Replace {{author.id}} with {{primary_author.id}} or {{authors.[#].id}}', details: oneLineTrim`The usage of {{author.id}} is no longer supported and should be replaced with either {{primary_author.id}} or {{authors.[#].id}}.
${multiAuthorDesc}
${authorHelperDocs}`, regex: /{{\s*?author\.id\s*?}}/g, helper: '{{author.id}}' }, 'GS001-DEPR-AUTH-SLUG': { level: 'error', fatal: false, rule: 'Replace {{author.slug}} with {{primary_author.slug}} or {{authors.[#].slug}}', details: oneLineTrim`The usage of {{author.slug}} is no longer supported and should be replaced with either {{primary_author.slug}} or {{authors.[#].slug}}.
${multiAuthorDesc}
${authorHelperDocs}`, regex: /{{\s*?author\.slug\s*?}}/g, helper: '{{author.slug}}' }, 'GS001-DEPR-AUTH-MAIL': { level: 'error', fatal: false, rule: 'Replace {{author.email}} with {{primary_author.email}} or {{authors.[#].email}}', details: oneLineTrim`The usage of {{author.email}} is no longer supported and should be replaced with either {{primary_author.email}} or {{authors.[#].email}}.
${multiAuthorDesc}
${authorHelperDocs}`, regex: /{{\s*?author\.email\s*?}}/g, helper: '{{author.email}}' }, 'GS001-DEPR-AUTH-MT': { level: 'error', fatal: false, rule: 'Replace {{author.meta_title}} with {{primary_author.meta_title}} or {{authors.[#].meta_title}}', details: oneLineTrim`The usage of {{author.meta_title}} is no longer supported and should be replaced with either {{primary_author.meta_title}} or {{authors.[#].meta_title}}.
${multiAuthorDesc}
${authorHelperDocs}`, regex: /{{\s*?author\.meta_title\s*?}}/g, helper: '{{author.meta_title}}' }, 'GS001-DEPR-AUTH-MD': { level: 'error', fatal: false, rule: 'Replace {{author.meta_description}} with {{primary_author.meta_description}} or {{authors.[#].meta_description}}', details: oneLineTrim`The usage of {{author.meta_description}} is no longer supported and should be replaced with either {{primary_author.meta_description}} or {{authors.[#].meta_description}}.
${multiAuthorDesc}
${authorHelperDocs}`, regex: /{{\s*?author\.meta_description\s*?}}/g, helper: '{{author.meta_description}}' }, 'GS001-DEPR-AUTH-NAME': { level: 'error', fatal: false, rule: 'Replace {{author.name}} with {{primary_author.name}} or {{authors.[#].name}}', details: oneLineTrim`The usage of {{author.name}} is no longer supported and should be replaced with either {{primary_author.name}} or {{authors.[#].name}}.
${multiAuthorDesc}
${authorHelperDocs}`, regex: /{{\s*?author\.name\s*?}}/g, helper: '{{author.name}}' }, 'GS001-DEPR-AUTH-BIO': { level: 'error', fatal: false, rule: 'Replace {{author.bio}} with {{primary_author.bio}} or {{authors.[#].bio}}', details: oneLineTrim`The usage of {{author.bio}} is no longer supported and should be replaced with either {{primary_author.bio}} or {{authors.[#].bio}}.
${multiAuthorDesc}
${authorHelperDocs}`, regex: /{{\s*?author\.bio\s*?}}/g, helper: '{{author.bio}}' }, 'GS001-DEPR-AUTH-LOC': { level: 'error', fatal: false, rule: 'Replace {{author.location}} with {{primary_author.location}} or {{authors.[#].location}}', details: oneLineTrim`The usage of {{author.location}} is no longer supported and should be replaced with either {{primary_author.location}} or {{authors.[#].location}}.
${multiAuthorDesc}
${authorHelperDocs}`, regex: /{{\s*?author\.location\s*?}}/g, helper: '{{author.location}}' }, 'GS001-DEPR-AUTH-WEB': { level: 'error', fatal: false, rule: 'Replace {{author.website}} with {{primary_author.website}} or {{authors.[#].website}}', details: oneLineTrim`The usage of {{author.website}} is no longer supported and should be replaced with either {{primary_author.website}} or {{authors.[#].website}}.
${multiAuthorDesc}
${authorHelperDocs}`, regex: /{{\s*?author\.website\s*?}}/g, helper: '{{author.website}}' }, 'GS001-DEPR-AUTH-TW': { level: 'error', fatal: false, rule: 'Replace {{author.twitter}} with {{primary_author.twitter}} or {{authors.[#].twitter}}', details: oneLineTrim`The usage of {{author.twitter}} is no longer supported and should be replaced with either {{primary_author.twitter}} or {{authors.[#].twitter}}.
${multiAuthorDesc}
${authorHelperDocs}`, regex: /{{\s*?author\.twitter\s*?}}/g, helper: '{{author.twitter}}' }, 'GS001-DEPR-AUTH-FB': { level: 'error', fatal: false, rule: 'Replace {{author.facebook}} with {{primary_author.facebook}} or {{authors.[#].facebook}}', details: oneLineTrim`The usage of {{author.facebook}} is no longer supported and should be replaced with either {{primary_author.facebook}} or {{authors.[#].facebook}}.
${multiAuthorDesc}
${authorHelperDocs}`, regex: /{{\s*?author\.facebook\s*?}}/g, helper: '{{author.facebook}}' }, 'GS001-DEPR-AUTH-PIMG': { level: 'error', fatal: false, rule: 'Replace {{author.profile_image}} with {{primary_author.profile_image}} or {{authors.[#].profile_image}}', details: oneLineTrim`The usage of {{author.profile_image}} is no longer supported and should be replaced with either {{primary_author.profile_image}} or {{authors.[#].profile_image}}.
${multiAuthorDesc}
${authorHelperDocs}`, regex: /{{\s*?author\.profile_image\s*?}}/g, helper: '{{author.profile_image}}' }, 'GS001-DEPR-AUTH-CIMG': { level: 'error', fatal: false, rule: 'Replace {{author.cover_image}} with {{primary_author.cover_image}} or {{authors.[#].cover_image}}', details: oneLineTrim`The usage of {{author.cover_image}} is no longer supported and should be replaced with either {{primary_author.cover_image}} or {{authors.[#].cover_image}}.
${multiAuthorDesc}
${authorHelperDocs}`, regex: /{{\s*?author\.cover_image\s*?}}/g, helper: '{{author.cover_image}}' }, 'GS001-DEPR-AUTH-URL': { level: 'error', fatal: false, rule: 'Replace {{author.url}} with {{primary_author.url}} or {{authors.[#].url}}', details: oneLineTrim`The usage of {{author.url}} is no longer supported and should be replaced with either {{primary_author.url}} or {{authors.[#].url}}.
${multiAuthorDesc}
${authorHelperDocs}`, regex: /{{\s*?author\.url\s*?}}/g, helper: '{{author.url}}' }, 'GS001-DEPR-PAUTH': { level: 'error', fatal: true, rule: 'Replace {{post.author}} with {{post.primary_author}} or {{authors.[#]}}', details: oneLineTrim`The usage of {{post.author}} is no longer supported and should be replaced with either {{post.primary_author}} or {{post.authors.[#]}}.
${multiAuthorDesc}
${authorHelperDocs}`, regex: /{{\s*?post\.author\s*?}}/g, helper: '{{post.author}}' }, 'GS001-DEPR-PAUTH-ID': { level: 'error', fatal: true, rule: 'Replace {{post.author.id}} with {{post.primary_author.id}} or {{authors.[#].id}}', details: oneLineTrim`The usage of {{post.author.id}} is no longer supported and should be replaced with either {{post.primary_author.id}} or {{post.authors.[#].id}}.
${multiAuthorDesc}
${authorHelperDocs}`, regex: /{{\s*?post\.author\.id\s*?}}/g, helper: '{{post.author.id}}' }, 'GS001-DEPR-PAUTH-SLUG': { level: 'error', fatal: true, rule: 'Replace {{post.author.slug}} with {{post.primary_author.slug}} or {{post.authors.[#].slug}}', details: oneLineTrim`The usage of {{post.author.slug}} is no longer supported and should be replaced with either {{post.primary_author.slug}} or {{post.authors.[#].slug}}.
${multiAuthorDesc}
${authorHelperDocs}`, regex: /{{\s*?post\.author\.slug\s*?}}/g, helper: '{{post.author.slug}}' }, 'GS001-DEPR-PAUTH-MAIL': { level: 'error', fatal: true, rule: 'Replace {{post.author.email}} with {{post.primary_author.email}} or {{post.authors.[#].email}}', details: oneLineTrim`The usage of {{post.author.email}} is no longer supported and should be replaced with either {{post.primary_author.email}} or {{post.authors.[#].email}}.
${multiAuthorDesc}
${authorHelperDocs}`, regex: /{{\s*?post\.author\.email\s*?}}/g, helper: '{{post.author.email}}' }, 'GS001-DEPR-PAUTH-MT': { level: 'error', fatal: true, 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 no longer supported and should be replaced with either {{post.primary_author.meta_title}} or {{post.authors.[#].meta_title}}.
${multiAuthorDesc}
${authorHelperDocs}`, regex: /{{\s*?post\.author\.meta_title\s*?}}/g, helper: '{{post.author.meta_title}}' }, 'GS001-DEPR-PAUTH-MD': { level: 'error', fatal: true, 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 no longer supported and should be replaced with either {{post.primary_author.meta_description}} or {{post.authors.[#].meta_description}}.
${multiAuthorDesc}
${authorHelperDocs}`, regex: /{{\s*?post\.author\.meta_description\s*?}}/g, helper: '{{post.author.meta_description}}' }, 'GS001-DEPR-PAUTH-NAME': { level: 'error', fatal: true, rule: 'Replace {{post.author.name}} with {{post.primary_author.name}} or {{post.authors.[#].name}}', details: oneLineTrim`The usage of {{post.author.name}} is no longer supported and should be replaced with either {{post.primary_author.name}} or {{post.authors.[#].name}}.
${multiAuthorDesc}
${authorHelperDocs}`, regex: /{{\s*?post\.author\.name\s*?}}/g, helper: '{{post.author.name}}' }, 'GS001-DEPR-PAUTH-BIO': { level: 'error', fatal: true, rule: 'Replace {{post.author.bio}} with {{post.primary_author.bio}} or {{post.authors.[#].bio}}', details: oneLineTrim`The usage of {{post.author.bio}} is no longer supported and should be replaced with either {{post.primary_author.bio}} or {{post.authors.[#].bio}}.
${multiAuthorDesc}
${authorHelperDocs}`, regex: /{{\s*?post\.author\.bio\s*?}}/g, helper: '{{post.author.bio}}' }, 'GS001-DEPR-PAUTH-LOC': { level: 'error', fatal: true, rule: 'Replace {{post.author.location}} with {{post.primary_author.location}} or {{post.authors.[#].location}}', details: oneLineTrim`The usage of {{post.author.location}} is no longer supported and should be replaced with either {{post.primary_author.location}} or {{post.authors.[#].location}}.
${multiAuthorDesc}
${authorHelperDocs}`, regex: /{{\s*?post\.author\.location\s*?}}/g, helper: '{{post.author.location}}' }, 'GS001-DEPR-PAUTH-WEB': { level: 'error', fatal: true, rule: 'Replace {{post.author.website}} with {{post.primary_author.website}} or {{post.authors.[#].website}}', details: oneLineTrim`The usage of {{post.author.website}} is no longer supported and should be replaced with either {{post.primary_author.website}} or {{post.authors.[#].website}}.
${multiAuthorDesc}
${authorHelperDocs}`, regex: /{{\s*?post\.author\.website\s*?}}/g, helper: '{{post.author.website}}' }, 'GS001-DEPR-PAUTH-TW': { level: 'error', fatal: true, rule: 'Replace {{post.author.twitter}} with {{post.primary_author.twitter}} or {{post.authors.[#].twitter}}', details: oneLineTrim`The usage of {{post.author.twitter}} is no longer supported and should be replaced with either {{post.primary_author.twitter}} or {{post.authors.[#].twitter}}.
${multiAuthorDesc}
${authorHelperDocs}`, regex: /{{\s*?post\.author\.twitter\s*?}}/g, helper: '{{post.author.twitter}}' }, 'GS001-DEPR-PAUTH-FB': { level: 'error', fatal: true, rule: 'Replace {{post.author.facebook}} with {{post.primary_author.facebook}} or {{post.authors.[#].facebook}}', details: oneLineTrim`The usage of {{post.author.facebook}} is no longer supported and should be replaced with either {{post.primary_author.facebook}} or {{post.authors.[#].facebook}}.
${multiAuthorDesc}
${authorHelperDocs}`, regex: /{{\s*?post\.author\.facebook\s*?}}/g, helper: '{{post.author.facebook}}' }, 'GS001-DEPR-PAUTH-PIMG': { level: 'error', fatal: true, 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 no longer supported and should be replaced with either {{post.primary_author.profile_image}} or {{post.authors.[#].profile_image}}.
${multiAuthorDesc}
${authorHelperDocs}`, regex: /{{\s*?post\.author\.profile_image\s*?}}/g, helper: '{{post.author.profile_image}}' }, 'GS001-DEPR-PAUTH-CIMG': { level: 'error', fatal: true, 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 no longer supported and should be replaced with either {{post.primary_author.cover_image}} or {{post.authors.[#].cover_image}}.
${multiAuthorDesc}
${authorHelperDocs}`, regex: /{{\s*?post\.author\.cover_image\s*?}}/g, helper: '{{post.author.cover_image}}' }, 'GS001-DEPR-PAUTH-URL': { level: 'error', fatal: true, rule: 'Replace {{post.author.url}} with {{post.primary_author.url}} or {{post.authors.[#].url}}', details: oneLineTrim`The usage of {{post.author.url}} is no longer supported and should be replaced with either {{post.primary_author.url}} or {{post.authors.[#].url}}.
${multiAuthorDesc}
${authorHelperDocs}`, regex: /{{\s*?post\.author\.url\s*?}}/g, helper: '{{post.author.url}}' }, 'GS001-DEPR-PAID': { level: 'error', fatal: true, 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}}.
Find more information about the object attributes of post here.`, regex: /{{\s*?post\.author_id\s*?}}/g, helper: '{{post.author_id}}' }, 'GS001-DEPR-NAUTH': { level: 'error', fatal: true, rule: 'Replace ../author with ../primary_author or ../authors.[#]', details: oneLineTrim`The usage of ../author is no longer supported and should be replaced with either ../primary_author or ../authors.[#].
${multiAuthorDesc}
${authorHelperDocs}`, regex: /{{\s*?(?:#|#if)?\s*?\.\.\/author(?:\.\S*?)?\s*?}}/g, helper: '{{../author}}' }, 'GS001-DEPR-IUA': { level: 'error', fatal: false, rule: 'Replace {{img_url author.*}} with {{img_url primary_author.*}} or .{img_url author.[#].*}}', details: oneLineTrim`The usage of {{img_url author.*}} is no longer supported and should be replaced with either {{img_url primary_author.*}} or {{img_url author.[#].*}}.
${multiAuthorDesc}
${authorHelperDocs}`, regex: /{{\s*?img_url\s*?(author.).*}}/g, helper: '{{img_url author.*}}' }, 'GS001-DEPR-AC': { level: 'error', fatal: false, 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}}.
Find more information about the object attributes of author here.`, regex: /{{\s*?author\.cover\s*?}}/g, helper: '{{author.cover}}' }, 'GS001-DEPR-AIMG': { level: 'error', fatal: false, 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}}.
Find more information about the object attributes of author here.`, regex: /{{\s*?author\.image\s*?}}/g, helper: '{{author.image}}' }, 'GS001-DEPR-PAC': { level: 'error', fatal: false, 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}}.
Find more information about the object attributes of author here.`, regex: /{{\s*?post\.author\.cover\s*?}}/g, helper: '{{post.author.cover}}' }, 'GS001-DEPR-AUTH-INCL': { level: 'error', fatal: false, rule: `Replace include="author" with include="authors"`, details: oneLineTrim`The usage of {{#get "posts" include="author"}} is no longer supported 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', fatal: false, rule: `fields="author" should be replaced with fields="authors"`, details: oneLineTrim`The usage of {{#get "posts" fields="author"}} is no longer supported 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', fatal: false, rule: `filter="author:[...]" should be replaced with filter="authors:[...]"`, details: oneLineTrim`The usage of {{#get "posts" filter="author:[...]"}} is no longer supported 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', fatal: false, rule: 'The {{#author}} block helper should be replaced with {{#primary_author}} or {{#foreach authors}}...{{/foreach}}', details: oneLineTrim`The usage of {{#author}} block helper outside of author.hbs is no longer supported and should be replaced with {{#primary_author}} or {{#foreach authors}}...{{/foreach}}.
${multiAuthorDesc}
${authorHelperDocs}`, regex: /{{\s*?#author\s*?}}/g, notValidIn: 'author.hbs', helper: '{{#author}}' }, 'GS001-DEPR-PAIMG': { level: 'error', fatal: false, 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}}.
Find more information about the object attributes of author here.`, regex: /{{\s*?post\.author\.image\s*?}}/g, helper: '{{post.author.image}}' }, 'GS001-DEPR-CON-AUTH': { level: 'error', fatal: false, rule: `The {{#if author.*}} block helper should be replaced with {{#if primary_author.*}} or {{#if authors.[#].*}}`, details: oneLineTrim`The usage of {{#if author.*}} is no longer supported and should be replaced with {{#if primary_author.*}} or {{#if authors.[#].*}}.
${multiAuthorDesc}
${authorHelperDocs}`, regex: /{{\s*?#if\s*?(author)(?:\.\w+)*?\s*?}}/g, helper: '{{#if author.*}}' }, 'GS001-DEPR-CON-PAUTH': { level: 'error', fatal: false, rule: `The {{#if post.author.*}} block helper should be replaced with {{#if post.primary_author.*}} or {{#if post.authors.[#].*}}`, details: oneLineTrim`The usage of {{#if post.author.*}} is no longer supported and should be replaced with {{#if post.primary_author.*}} or {{#if post.authors.[#].*}}.
${multiAuthorDesc}
${authorHelperDocs}`, regex: /{{\s*?#if\s*?(?:post\.)(author)(?:\.\w+)*?\s*?}}/g, helper: '{{#if post.author.*}}' }, 'GS001-DEPR-CON-AC': { level: 'error', fatal: false, 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}}.
Find more information about the object attributes of author here.`, regex: /{{\s*?#if\s*?author\.cover\s*?}}/g, helper: '{{#if author.cover}}' }, 'GS001-DEPR-CON-AIMG': { level: 'error', fatal: false, 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}}.
Find more information about the object attributes of author here.`, regex: /{{\s*?#if\s*?author\.image\s*?}}/g, helper: '{{#if author.image}}' }, 'GS001-DEPR-CON-PAC': { level: 'error', fatal: false, 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}}.
Find more information about the object attributes of author here.`, regex: /{{\s*?#if\s*?post\.author\.cover\s*?}}/g, helper: '{{#if post.author.cover}}' }, 'GS001-DEPR-CON-PAIMG': { level: 'error', fatal: false, 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}}.
Find more information about the object attributes of author here.`, regex: /{{\s*?#if\s*?post\.author\.image\s*?}}/g, helper: '{{#if post.author.image}}' }, 'GS001-DEPR-LABS-MEMBERS': { level: 'error', rule: 'Replace {{@labs.members}} with {{@site.members_enabled}}', details: oneLineTrim`Usage of {{@labs.members}} is no longer supported and should be replaced with {{@site.members_enabled}}
Find more information about the @site property here.`, regex: /@labs\.members/g, helper: '{{@labs.members}}' }, 'GS001-DEPR-SPL': { level: 'error', fatal: true, rule: 'Remove uses of {{@site.permalinks}}', 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-BPL': { level: 'error', fatal: true, rule: 'Remove uses of {{@blog.permalinks}}', 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-SGF': { level: 'error', fatal: true, rule: 'Replace {{@site.ghost_foot}} with {{ghost_foot}}', details: oneLineTrim`The usage of {{@site.ghost_foot}} is no longer supported and should be replaced with {{ghost_foot}}.
Find more information about the {{ghost_foot}} property here.`, regex: /{{\s*?@site\.ghost_foot\s*?}}/g, helper: '{{@site.ghost_foot}}' }, 'GS001-DEPR-SGH': { level: 'error', fatal: true, rule: 'Replace {{@site.ghost_head}} with {{ghost_head}}', details: oneLineTrim`The usage of {{@site.ghost_head}} is no longer supported and should be replaced with {{ghost_head}}.
Find more information about the {{ghost_head}} property here.`, regex: /{{\s*?@site\.ghost_head\s*?}}/g, helper: '{{@site.ghost_head}}' }, 'GS001-DEPR-LANG': { level: 'error', rule: 'Replace {{lang}} with {{@site.locale}}', details: oneLineTrim`The usage of {{lang}} is no longer supported and should be replaced with {{@site.locale}}.
Find more information about the @site.locale property here.`, regex: /{{\s*?lang\s*?}}/g, helper: '{{lang}}' }, 'GS001-DEPR-SITE-LANG': { level: 'error', fatal: false, rule: 'Replace {{@site.lang}} with {{@site.locale}}', details: oneLineTrim`The usage of {{@site.lang}} is no longer supported and shoud be replaced with {{@site.locale}}.
Find more information about the @site.locale property here.`, regex: /@site\.lang/g, helper: '{{@site.lang}}' }, 'GS001-DEPR-USER-GET': { level: 'error', fatal: false, rule: `Replace {{#get "users"}} with {{#get "authors"}}`, details: oneLineTrim`The usage of {{#get "users"}} is no longer supported and 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-CURR-SYM': { level: 'error', fatal: false, rule: 'Replace {{[#].currency_symbol}} with {{price currency=currency}}.', details: oneLineTrim`The currency_symbol attribute is no longer supported in favour of passing the currency to updated {{price}} helper.
Find more information about the updated {{price}} helper here.`, helper: '{{[#].currency_symbol}}', regex: /currency_symbol/g }, 'GS010-PJ-CUST-THEME-SETTINGS-DESCRIPTION-LENGTH': { level: 'warning', rule: 'package.json property config.custom contains an entry with a description that is too long', details: oneLineTrim`config.custom entry description should be less than 100 characters so that it is displayed correctly.
Check the config.custom documentation for further information.` }, 'GS010-PJ-CUST-THEME-SETTINGS-VISIBILITY-SYNTAX': { level: 'error', rule: 'package.json property config.custom contains an entry with visibility that contains invalid syntax', details: oneLineTrim`config.custom entry visibility should be valid nql.
Check the config.custom documentation for further information.` }, 'GS010-PJ-CUST-THEME-SETTINGS-VISIBILITY-VALUE': { level: 'error', rule: 'package.json property config.custom contains an entry with visibility that references a custom setting that does not exist', details: oneLineTrim`config.custom entry visibility should be only reference other custom settings.
Check the config.custom documentation for further information.` }, 'GS110-NO-MISSING-PAGE-BUILDER-USAGE': { level: 'error', rule: 'Not all page features are being used', details: oneLineTrim`This error only applies to pages created with the Beta editor. Some page features used by Ghost via the {{@page}} global are not implemented in this theme.  Find more information about the {{@page}} global here.` }, 'GS110-NO-UNKNOWN-PAGE-BUILDER-USAGE': { level: 'error', fatal: true, rule: 'Unsupported page builder feature used', details: oneLineTrim`A page feature used via the {{@page}} global was detected but is not supported by this version of Ghost. Please upgrade to the latest version for full access.  You can find more information about the {{@page}} global here.` }, 'GS120-NO-UNKNOWN-GLOBALS': { level: 'error', rule: 'No unknown global helper used', details: oneLineTrim`A global helper was detected that is not supported by this version of Ghost. Check the helpers 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. delete previousRules['GS010-PJ-GHOST-API-V01']; 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: true } };