Skip to content

Commit 431a14a

Browse files
Improve yuidoc fixin logic
1 parent 88eef9d commit 431a14a

File tree

7 files changed

+225
-85
lines changed

7 files changed

+225
-85
lines changed

lib/fix-borked-yuidoc-files.js

Lines changed: 18 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1,85 +1,8 @@
11
import fs from 'fs-extra'
2-
import lodash from 'lodash'
32
import semverUtils from 'semver-utils'
4-
5-
const { without } = lodash
6-
7-
const classItemKeys = [
8-
'access',
9-
'category',
10-
'chainable',
11-
'class',
12-
'default',
13-
'deprecated',
14-
'deprecationMessage',
15-
'description',
16-
'file',
17-
'filetype',
18-
'final',
19-
'itemtype',
20-
'line',
21-
'module',
22-
'name',
23-
'namespace',
24-
'params',
25-
'return',
26-
'see',
27-
'since',
28-
'static',
29-
'tagname',
30-
'throws',
31-
'type',
32-
]
33-
34-
const normalizeItem = item => {
35-
let normalizedItem = {}
36-
37-
let encounteredDescription = false
38-
let finishedNormalization = false
39-
let newDescription = ''
40-
41-
Object.keys(item).forEach(key => {
42-
if (key === 'description') {
43-
encounteredDescription = true
44-
}
45-
46-
if (!encounteredDescription || finishedNormalization) {
47-
normalizedItem[key] = item[key]
48-
} else {
49-
if (key === 'description' || !classItemKeys.includes(key)) {
50-
let content = item[key]
51-
52-
if (key === 'description') {
53-
newDescription = content + '\n'
54-
55-
if (content.endsWith('}')) {
56-
newDescription += '\n'
57-
}
58-
return
59-
}
60-
61-
// For cases where we have @decorator(args), other cases are @decorator x
62-
if (!content.startsWith('(')) {
63-
content = ' ' + content
64-
}
65-
66-
newDescription += ' @' + key + content + '\n'
67-
} else {
68-
normalizedItem[key] = item[key]
69-
finishedNormalization = true
70-
normalizedItem.description = newDescription
71-
}
72-
}
73-
})
74-
75-
const keysToNormalize = without(Object.keys(item), ...Object.keys(normalizedItem))
76-
77-
console.log(
78-
`File name: ${item.file} | Line number: ${item.line} | Faulty keys: ${keysToNormalize}`
79-
)
80-
81-
return normalizedItem
82-
}
3+
import { normalizeYuiDocClassItem } from './yuidoc-fixer/normalize-yui-doc-class-item'
4+
import { yuiDocClassItemKeys } from './yuidoc-fixer/yui-doc-class-item-keys'
5+
import { normalizeYuiDocClass } from './yuidoc-fixer/normalize-yui-doc-class'
836

847
/**
858
* In ember 3.10 and above we introduced decorators.
@@ -117,24 +40,35 @@ export default async function fixBorkedYuidocFiles(file) {
11740

11841
const doc = await fs.readJson(file)
11942

43+
let normalizedClasses = Object.keys(doc.classes).reduce((result, klass) => {
44+
result[klass] = normalizeYuiDocClass(doc.classes[klass])
45+
return result
46+
}, {})
47+
12048
let normalizedClassItems = doc.classitems.map(item => {
12149
let keys = Object.keys(item)
12250
let locationOfDescriptionField = keys.indexOf('description')
12351

12452
if (
12553
locationOfDescriptionField === -1 ||
126-
classItemKeys.includes(keys[locationOfDescriptionField + 1])
54+
yuiDocClassItemKeys.includes(keys[locationOfDescriptionField + 1])
12755
) {
12856
return item
129-
} else {
130-
return normalizeItem(item)
13157
}
58+
59+
return normalizeYuiDocClassItem(item)
13260
})
13361

13462
let newDoc = {}
13563

13664
Object.keys(doc).forEach(key => {
137-
newDoc[key] = key === 'classitems' ? normalizedClassItems : doc[key]
65+
if (key === 'classitems') {
66+
newDoc[key] = normalizedClassItems
67+
} else if (key === 'classes') {
68+
newDoc[key] = normalizedClasses
69+
} else {
70+
newDoc[key] = doc[key]
71+
}
13872
})
13973

14074
await fs.move(file, originalFileBackup)
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import moduleData from 'ember-rfc176-data'
2+
import keyfinder from 'keyfinder'
3+
import { uniq } from 'lodash'
4+
5+
export const emberKnownEntityNames = uniq(keyfinder(moduleData, 'export'))
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { toLower } from 'lodash'
2+
import { yuiDocClassItemKeys } from './yui-doc-class-item-keys'
3+
import { emberKnownEntityNames } from './emberKnownEntityNames'
4+
5+
export const normalizeYuiDocClassItem = item => {
6+
let normalizedItem = {}
7+
8+
let encounteredDescription = false
9+
let finishedNormalization = false
10+
let newDescription = ''
11+
let faultyKeys = []
12+
13+
Object.keys(item).forEach(key => {
14+
if (key === 'description') {
15+
encounteredDescription = true
16+
}
17+
18+
if (!encounteredDescription || finishedNormalization) {
19+
normalizedItem[key] = item[key]
20+
} else {
21+
if (key === 'description' || !yuiDocClassItemKeys.includes(key)) {
22+
let content = item[key]
23+
24+
if (key === 'description') {
25+
newDescription = content + '\n'
26+
27+
if (content.endsWith('}')) {
28+
newDescription += '\n'
29+
}
30+
return
31+
}
32+
33+
// For cases where we have @decorator(args), other cases are @decorator x
34+
if (!content.startsWith('(')) {
35+
content = ' ' + content
36+
}
37+
38+
let transformedKey = key
39+
40+
if (emberKnownEntityNames.map(toLower).includes(key)) {
41+
transformedKey = emberKnownEntityNames.find(
42+
name => name.toLowerCase() === key.toLowerCase()
43+
)
44+
}
45+
46+
newDescription += ' @' + transformedKey + content + '\n'
47+
48+
faultyKeys.push(transformedKey)
49+
} else {
50+
normalizedItem[key] = item[key]
51+
finishedNormalization = true
52+
normalizedItem.description = newDescription
53+
}
54+
}
55+
})
56+
57+
console.log(`File name: ${item.file} | Line number: ${item.line} | Faulty keys: ${faultyKeys}`)
58+
59+
return normalizedItem
60+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { normalizeYuiDocClassItem } from './normalize-yui-doc-class-item'
2+
import { yuiDocClassItemKeys } from './yui-doc-class-item-keys'
3+
4+
export const normalizeYuiDocClass = klass => {
5+
if (!klass.description) {
6+
return klass
7+
}
8+
9+
let keys = Object.keys(klass)
10+
let locationOfDescriptionField = keys.indexOf('description')
11+
12+
if (
13+
locationOfDescriptionField === -1 ||
14+
yuiDocClassItemKeys.includes(keys[locationOfDescriptionField + 1])
15+
) {
16+
return klass
17+
}
18+
19+
return normalizeYuiDocClassItem(klass)
20+
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import { without } from 'lodash'
2+
3+
const originalYuiDocClassItemKeys = [
4+
'async', // bool, custom events can fire the listeners in a setTimeout
5+
'author', // author best for projects and modules, but can be used anywhere // multi
6+
'attribute', // YUI attributes / custom element attributes
7+
'beta', // module maturity identifier
8+
'broadcast', // bool, events
9+
'bubbles', // custom events that bubble
10+
'category', // modules can be in multiple categories
11+
'chainable', // methods that return the host object
12+
'class', // pseudo class
13+
'conditional', // conditional module
14+
'config', // a config param (not an attribute, so no change events)
15+
'const', // not standardized yet, converts to final property
16+
'constructs', // factory methods (not yet used)
17+
'constructor', // this is a constructor
18+
'content', // permitted content for an @element
19+
'contributor', // like author
20+
'default', // property/attribute default value
21+
'deprecated', // please specify what to use instead
22+
'description', // can also be free text at the beginning of a comment is
23+
'emitfacade', // bool, YUI custom event can have a dom-like event facade
24+
'element', // Web Components custom element
25+
'event', // YUI custom event
26+
'evil', // uses eval
27+
'extension', // this is an extension for [entity]
28+
'extensionfor', // this is an extension for [entity]
29+
'extension_for', // this is an extension for [entity]
30+
'example', // 0..n code snippets. snippets can also be embedded in the desc
31+
'experimental', // module maturity identifier
32+
'extends', // pseudo inheritance
33+
'file', // file name (used by the parser)
34+
'final', // not meant to be changed
35+
'fireonce', // bool, YUI custom event config allows
36+
'for', // used to change class context
37+
'global', // declare your globals
38+
'icon', // project icon(s)
39+
'implements', // Implements Interface
40+
'in', // indicates module this lives in (obsolete now)
41+
'initonly', // attribute writeonce value
42+
'injects', // injects {HTML|script|CSS}
43+
'interface', // Is Interface / Interface for an @element
44+
'knownissue', // 0..n known issues for your consumption
45+
'line', // line number for the comment block (used by the parser)
46+
'method', // a method
47+
'module', // YUI module name
48+
'main', // Description for the module
49+
'namespace', // Y.namespace, used to fully qualify class names
50+
'optional', // For optional attributes
51+
'required', // For required attributes
52+
'param', // member param
53+
'parents', // permitted parents for an @element
54+
'plugin', // this is a plugin for [entityl]
55+
'preventable', // YUI custom events can be preventable ala DOM events
56+
'private', // > access
57+
'project', // project definition, one per source tree allowed
58+
'property', // a regular-ole property
59+
'protected', // > access
60+
'public', // > access
61+
'queuable', // bool, events
62+
'readonly', // YUI attribute config
63+
'requires', // YUI module requirements
64+
'return', // {type} return desc -- returns is converted to this
65+
'see', // 0..n things to look at
66+
'since', // when it was introduced
67+
'static', // static
68+
'submodule', // YUI submodule
69+
'throws', // {execption type} description
70+
'title', // this should be something for the project description
71+
'todo', // 0..n things to revisit eventually (hopefully)
72+
'type', // the var type
73+
'url', // project url(s)
74+
'uses', // 0..n compents mixed (usually, via augment) into the prototype
75+
'value', // the value of a constant
76+
'writeonce', // YUI attribute config
77+
]
78+
79+
const additionalDocumentationKeywords = [
80+
'access',
81+
'tagname',
82+
'itemtype',
83+
'params',
84+
'name',
85+
'is_constructor',
86+
]
87+
88+
const keywordsInOurProjects = ['readonly']
89+
90+
export const yuiDocClassItemKeys = without(
91+
[...additionalDocumentationKeywords, ...originalYuiDocClassItemKeys],
92+
...keywordsInOurProjects
93+
)

package.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
"cheerio": "^1.0.0-rc.2",
2929
"compare-versions": "^3.4.0",
3030
"download": "^7.1.0",
31+
"ember-rfc176-data": "^0.3.9",
3132
"esm": "^3.2.25",
3233
"fs-extra": "^7.0.0",
3334
"glob": "^7.1.3",
@@ -36,6 +37,7 @@
3637
"http-server": "^0.11.1",
3738
"human-size": "^1.1.0",
3839
"inflected": "^2.0.4",
40+
"keyfinder": "^1.0.0",
3941
"lodash": "^4.17.11",
4042
"marked": "^0.5.1",
4143
"minimist": "^1.2.0",
@@ -67,5 +69,7 @@
6769
"engines": {
6870
"node": "8"
6971
},
70-
"cacheDirectories": ["tmp"]
72+
"cacheDirectories": [
73+
"tmp"
74+
]
7175
}

yarn.lock

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -610,6 +610,11 @@ ecstatic@^3.0.0:
610610
minimist "^1.1.0"
611611
url-join "^2.0.5"
612612

613+
ember-rfc176-data@^0.3.9:
614+
version "0.3.9"
615+
resolved "https://registry.yarnpkg.com/ember-rfc176-data/-/ember-rfc176-data-0.3.9.tgz#44b6e051ead6c044ea87bd551f402e2cf89a7e3d"
616+
integrity sha512-EiTo5YQS0Duy0xp9gCP8ekzv9vxirNi7MnIB4zWs+thtWp/mEKgf5mkiiLU2+oo8C5DuavVHhoPQDmyxh8Io1Q==
617+
613618
end-of-stream@^1.0.0, end-of-stream@^1.1.0:
614619
version "1.4.1"
615620
resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43"
@@ -1245,6 +1250,11 @@ into-stream@^3.1.0:
12451250
from2 "^2.1.1"
12461251
p-is-promise "^1.1.0"
12471252

1253+
is-array@^1.0.1:
1254+
version "1.0.1"
1255+
resolved "https://registry.yarnpkg.com/is-array/-/is-array-1.0.1.tgz#e9850cc2cc860c3bc0977e84ccf0dd464584279a"
1256+
integrity sha1-6YUMwsyGDDvAl36EzPDdRkWEJ5o=
1257+
12481258
is-arrayish@^0.2.1:
12491259
version "0.2.1"
12501260
resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
@@ -1269,6 +1279,11 @@ is-fullwidth-code-point@^2.0.0:
12691279
version "2.0.0"
12701280
resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f"
12711281

1282+
is-function@^1.0.1:
1283+
version "1.0.1"
1284+
resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.1.tgz#12cfb98b65b57dd3d193a3121f5f6e2f437602b5"
1285+
integrity sha1-Es+5i2W1fdPRk6MSH19uL0N2ArU=
1286+
12721287
is-natural-number@^4.0.1:
12731288
version "4.0.1"
12741289
resolved "https://registry.yarnpkg.com/is-natural-number/-/is-natural-number-4.0.1.tgz#ab9d76e1db4ced51e35de0c72ebecf09f734cde8"
@@ -1373,6 +1388,15 @@ jsonfile@^4.0.0:
13731388
optionalDependencies:
13741389
graceful-fs "^4.1.6"
13751390

1391+
keyfinder@^1.0.0:
1392+
version "1.0.0"
1393+
resolved "https://registry.yarnpkg.com/keyfinder/-/keyfinder-1.0.0.tgz#0102750c5eebf4e6e840b1257d5a86ac96e58ef9"
1394+
integrity sha1-AQJ1DF7r9OboQLElfVqGrJbljvk=
1395+
dependencies:
1396+
is-array "^1.0.1"
1397+
is-function "^1.0.1"
1398+
is-object "^1.0.1"
1399+
13761400
13771401
version "3.0.0"
13781402
resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.0.0.tgz#44923ba39e68b12a7cec7df6c3268c031f2ef373"

0 commit comments

Comments
 (0)