Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions entry_types/scrolled/package/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,14 @@ module.exports = {
"patterns": ["**/entryState/**", "../**/entryState"]
}]
}
},
{
// Directories passed to documentation.js in
// .github/workflows/docs.yml.
"files": ["src/**/*.js", "spec/support/**/*.js"],
"rules": {
"documented-in-toc": "error"
}
}
]
};
3 changes: 3 additions & 0 deletions entry_types/scrolled/package/documentation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ toc:
children:
- frontend_contentElementTypes
- frontend_widgetTypes
- frontend_contentElementErrorBoundary
- name: Editor API
description: |
Main entry point of editor API to register new content element types.
Expand Down Expand Up @@ -45,6 +46,7 @@ toc:
- useLegalInfo
- useMediaMuted
- usePortraitOrientation
- usePrivacyLink
- useShareProviders
- useShareUrl
- useTheme
Expand All @@ -60,6 +62,7 @@ toc:
- normalizeSeed
- renderInEntry
- renderInContentElement
- renderInEntryWithContentElementLifecycle
- renderHookInEntry
- name: Storybook Support
description: |
Expand Down
2 changes: 1 addition & 1 deletion entry_types/scrolled/package/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@
},
"scripts": {
"test": "jest",
"lint": "eslint",
"lint": "eslint --rulesdir ../../../node_modules/pageflow/config/eslint-rules",
"start-storybook": "storybook dev --port 8001",
"build-storybook": "storybook build -o .storybook/out",
"snapshot": "storybook build --quiet -o .storybook/out && PERCY_TOKEN=${PERCY_TOKEN:-$PT} percy storybook .storybook/out"
Expand Down
3 changes: 2 additions & 1 deletion entry_types/scrolled/package/src/frontend/api/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ export const api = {
* typeName (string), configuration (object), fallback (function returning
* default UI), and children (content element).
*
* @property {React.Component} contentElementErrorBoundary
* @name frontend_contentElementErrorBoundary
* @type {React.Component}
*/
contentElementErrorBoundary: undefined
}
12 changes: 12 additions & 0 deletions package/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,18 @@ module.exports = {
{
"files": ["spec/**/*.js", "src/testHelpers/**/*.js"],
"extends": ["plugin:jest/recommended"]
},
{
// Directories passed to documentation.js in
// .github/workflows/docs.yml.
"files": [
"src/editor/**/*.js",
"src/ui/**/*.js",
"src/testHelpers/**/*.js"
],
"rules": {
"documented-in-toc": "error"
}
}
]
};
125 changes: 125 additions & 0 deletions package/config/eslint-rules/documented-in-toc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
const fs = require('fs');
const path = require('path');
const yaml = require('js-yaml');

// JSDoc comments on these are either nested under another item or
// excluded from the generated docs, so they do not need toc entries.
const skippedTags = /@(private|internal|ignore|memberof)\b/;

module.exports = {
meta: {
type: 'suggestion',
docs: {
description:
'Ensure JSDoc documented top level items are listed in the toc ' +
'of documentation.yml. Otherwise they render at an arbitrary ' +
'spot at the end of the generated docs.'
},
schema: []
},

create(context) {
const config = findTocConfig(path.dirname(context.getFilename()));

if (!config) {
return {};
}

const sourceCode = context.getSourceCode();

return {
Program(program) {
program.body.forEach(statement => {
const comment = jsdocCommentBefore(statement);

if (!comment || skippedTags.test(comment.value)) {
return;
}

const name = documentedName(comment, statement);

if (name && !config.names.has(name)) {
context.report({
loc: comment.loc,
message:
`'${name}' has a JSDoc comment, but is not listed in the ` +
`toc in ${config.relativePath}. Add it to the section ` +
'where it should show up in the generated docs.'
});
}
});
}
};

function jsdocCommentBefore(statement) {
const comments = sourceCode.getCommentsBefore(statement);
const comment = comments[comments.length - 1];

return comment &&
comment.type === 'Block' &&
comment.value.startsWith('*') ? comment : null;
}
}
};

function documentedName(comment, statement) {
const tagMatch = comment.value.match(/@(?:name|alias)\s+([\w.#]+)/);

if (tagMatch) {
return tagMatch[1];
}

return declaredName(statement);
}

function declaredName(statement) {
switch (statement.type) {
case 'ExportNamedDeclaration':
case 'ExportDefaultDeclaration':
return statement.declaration && declaredName(statement.declaration);
case 'FunctionDeclaration':
case 'ClassDeclaration':
return statement.id && statement.id.name;
case 'VariableDeclaration':
return statement.declarations[0].id.type === 'Identifier' ?
statement.declarations[0].id.name : null;
default:
return null;
}
}

const configCache = new Map();

function findTocConfig(directory) {
if (configCache.has(directory)) {
return configCache.get(directory);
}

const configPath = path.join(directory, 'documentation.yml');
let config;

if (fs.existsSync(configPath)) {
config = loadTocConfig(configPath);
}
else {
const parent = path.dirname(directory);
config = parent === directory ? null : findTocConfig(parent);
}

configCache.set(directory, config);
return config;
}

function loadTocConfig(configPath) {
const toc = yaml.safeLoad(fs.readFileSync(configPath, 'utf8')).toc || [];
const names = new Set();

toc.forEach(section =>
(section.children || []).forEach(child => names.add(child))
);

return {
names,
relativePath: path.relative(process.cwd(), configPath)
};
}
3 changes: 3 additions & 0 deletions package/documentation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,15 @@ toc:
- EditConfigurationView
- ReferenceInputView
- FileInputView
- OembedUrlInputView

- name: Editor - Misc Views
description: |
General purpose Backbone views and mixins exported by `pageflow/editor`.
children:
- modelLifecycleTrackingView
- DropDownButtonView
- DestroyMenuItem
- ListView
- ModelThumbnailView

Expand Down Expand Up @@ -132,4 +134,5 @@ toc:
children:
- factories
- setupGlobals
- useFakeFeatures
- useFakeTranslations
2 changes: 1 addition & 1 deletion package/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
},
"scripts": {
"test": "jest",
"lint": "eslint"
"lint": "eslint --rulesdir config/eslint-rules"
},
"dependencies": {
"backbone-events-standalone": "^0.2.7",
Expand Down
Loading