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
}
};