Skip to content

Commit

Permalink
INCOMPLETE
Browse files Browse the repository at this point in the history
1. Add tests (for desired features added to docs) -> implement
2. (apparent problem in eslint itself with our use of Program:exit):
3. Could also use this approach for checking consistency between function calls and jsdoc argument signature types; compile to WebAssembly
test(`no-undefined-types`): issues gajus#507
  • Loading branch information
brettz9 committed May 15, 2021
1 parent db1f289 commit e7694ef
Show file tree
Hide file tree
Showing 5 changed files with 213 additions and 6 deletions.
28 changes: 27 additions & 1 deletion .README/rules/no-undefined-types.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,38 @@ array's items will be considered as defined for the purposes of that tag.

#### Options

An option object may have the following key:
An option object may have the following keys, helping indicate types or
file sources of types:

- `definedTypes` - This array can be populated to indicate other types which
are automatically considered as defined (in addition to globals, etc.).
Defaults to an empty array.

- `entryFiles` - Array of entry files objects indicating JavaScript or HTML
files whose `import` or `require` statements should be resolved recursively
and be analyzed for `@typedef`'s, globals, etc. (see `typeSources`) to treat
as "defined" for the purposes of this rule. Each object should have a
`file` array and with an optional `node` boolean property to indicate whether
to use the Node Resolution Algorithm (e.g., for Node.js) and/or a `cjs`
boolean property (if following `require`) properties. Set one of the `file`
items to `<main>`, `<exports>`, `<exports.imports>`, or `<exports.require>`
to use the file referenced in the correpsonding property in `package.json`.

- `jsdocConfig` - Object with:
- `file` string pointing to a path for a
[jsdoc config file](https://jsdoc.app/about-configuring-jsdoc.html)
which will be parsed for [input files](https://jsdoc.app/about-configuring-jsdoc.html#specifying-input-files),
including `include`, `exclude`, `includePattern`, and `excludePattern`
properties within the file as well as `opts.recurse`. See `entryFiles`
on how the (JavaScript) files will be treated (with
`sourceType: 'module'` in the jsdoc config file causing "cjs" to be
set to `false`).

- `typeSources` - Array with `globals`, `exports`, and/or `locals` indicating
the source types that will be treated as valid types when found in the
current file or any entry files (`locals` will only apply to the
current file). Defaults to `['typedefs', 'globals', 'exports', 'locals']`.

|||
|---|---|
|Context|everywhere|
Expand Down
53 changes: 52 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7999,12 +7999,38 @@ array's items will be considered as defined for the purposes of that tag.
<a name="eslint-plugin-jsdoc-rules-no-undefined-types-options-18"></a>
#### Options

An option object may have the following key:
An option object may have the following keys, helping indicate types or
file sources of types:

- `definedTypes` - This array can be populated to indicate other types which
are automatically considered as defined (in addition to globals, etc.).
Defaults to an empty array.

- `entryFiles` - Array of entry files objects indicating JavaScript or HTML
files whose `import` or `require` statements should be resolved recursively
and be analyzed for `@typedef`'s, globals, etc. (see `typeSources`) to treat
as "defined" for the purposes of this rule. Each object should have a
`file` array and with an optional `node` boolean property to indicate whether
to use the Node Resolution Algorithm (e.g., for Node.js) and/or a `cjs`
boolean property (if following `require`) properties. Set one of the `file`
items to `<main>`, `<exports>`, `<exports.imports>`, or `<exports.require>`
to use the file referenced in the correpsonding property in `package.json`.

- `jsdocConfig` - Object with:
- `file` string pointing to a path for a
[jsdoc config file](https://jsdoc.app/about-configuring-jsdoc.html)
which will be parsed for [input files](https://jsdoc.app/about-configuring-jsdoc.html#specifying-input-files),
including `include`, `exclude`, `includePattern`, and `excludePattern`
properties within the file as well as `opts.recurse`. See `entryFiles`
on how the (JavaScript) files will be treated (with
`sourceType: 'module'` in the jsdoc config file causing "cjs" to be
set to `false`).

- `typeSources` - Array with `globals`, `exports`, and/or `locals` indicating
the source types that will be treated as valid types when found in the
current file or any entry files (`locals` will only apply to the
current file). Defaults to `['typedefs', 'globals', 'exports', 'locals']`.

|||
|---|---|
|Context|everywhere|
Expand Down Expand Up @@ -8543,6 +8569,31 @@ class Test {
return this;
}
}

import {myTypesA} from '../internal/file.js'; // ERROR
import {myTypesB} from '../internal/file.js'; // NO ERROR

/**
* @typedef newType
* @property {myTypesA.someType} someProp - Some prop.
*/

/**
* @param {newType} arg - Arg.
*/
function myFunctionA(arg) {
return arg;
}

/**
* @param {myTypesB.someType} arg - Arg.
*/
function myFunctionB(arg) {
return arg;
}

export {myFunctionA, myFunctionB};
// "jsdoc/no-undefined-types": ["error"|"warn", {"entryFiles":[]}]
````


Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"@es-joy/jsdoccomment": "^0.4.4",
"comment-parser": "1.1.5",
"debug": "^4.3.1",
"es-file-traverse": "^0.10.0",
"esquery": "^1.4.0",
"jsdoctypeparser": "^9.0.0",
"lodash": "^4.17.21",
Expand Down
99 changes: 95 additions & 4 deletions src/rules/noUndefinedTypes.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import {
getJSDocComment,
} from '@es-joy/jsdoccomment';
import {
traverse as esFileTraverse,
} from 'es-file-traverse';
import {
parse as parseType, traverse,
} from 'jsdoctypeparser';
Expand All @@ -23,9 +26,9 @@ const stripPseudoTypes = (str) => {
return str && str.replace(/(?:\.|<>|\.<>|\[\])$/u, '');
};

export default iterateJsdoc(({
export default iterateJsdoc(async ({
context,
node,
node: jsdocNode,
report,
settings,
sourceCode,
Expand All @@ -34,7 +37,57 @@ export default iterateJsdoc(({
const {scopeManager} = sourceCode;
const {globalScope} = scopeManager;

const {definedTypes = []} = context.options[0] || {};
const {
definedTypes = [],
entryFiles = [
// {file, cjs, node}
],
jsdocConfig: {file: jsdocConfigFile},
typeSources = ['typedefs', 'globals', 'exports', 'locals'],
} = context.options[0] || {};

// eslint-disable-next-line no-console
console.log('entryFiles', entryFiles, jsdocConfigFile, typeSources);

// No async rules yet per ESLint Discord
// chat response from nzakas
await Promise.all(entryFiles.map(({file, node, cjs}) => {
if ([
'<main>', '<exports>', '<exports.imports>', '<exports.require>',
].includes(file)) {
// Todo: Replace `file` with `package.json`-pointed value
}

return esFileTraverse({
/**
* @callback PromiseReturner
* @returns {Promise<void>}
*/
/**
* @typedef {PlainObject} ESFileTraverseInfo
* @property {string} fullPath
* @property {string} text
* @property {AST} ast
* @property {"esm"|"cjs"|"amd"} [type]
* @property {PromiseReturner[]} [promMethods]
* @property {Set<string>} [resolvedSet]
*/
/**
* @param {"enter"|"exit"} state
* @param {ESFileTraverseInfo} info
* @returns {void}
*/
callback (state, info) {
// Todo: Handle
// eslint-disable-next-line no-console
console.log('state', state, info);
},

cjs,
file,
node,
});
}));

let definedPreferredTypes = [];
const {preferredTypes, structuredTags, mode} = settings;
Expand Down Expand Up @@ -77,7 +130,7 @@ export default iterateJsdoc(({
.value();

const ancestorNodes = [];
let currentScope = scopeManager.acquire(node);
let currentScope = scopeManager.acquire(jsdocNode);

while (currentScope && currentScope.block.type !== 'Program') {
ancestorNodes.push(currentScope.block);
Expand Down Expand Up @@ -182,6 +235,44 @@ export default iterateJsdoc(({
},
type: 'array',
},
entryFiles: {
items: {
properties: {
cjs: {
type: 'boolean',
},
file: {
items: {
type: 'string',
},
type: 'array',
},
node: {
type: 'boolean',
},
},
require: ['file'],
type: 'object',
},
type: 'array',
},
jsdocConfig: {
properties: {
file: {
type: 'string',
},
},
type: 'object',
},
typeSources: {
items: {
enum: [
'globals', 'exports', 'locals',
],
type: 'string',
},
type: 'array',
},
},
type: 'object',
},
Expand Down
38 changes: 38 additions & 0 deletions test/rules/assertions/noUndefinedTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -997,5 +997,43 @@ export default {
`,
parser: require.resolve('@typescript-eslint/parser'),
},
{
code: `
import {myTypesA} from '../internal/file.js'; // ERROR
import {myTypesB} from '../internal/file.js'; // NO ERROR
/**
* @typedef newType
* @property {myTypesA.someType} someProp - Some prop.
*/
/**
* @param {newType} arg - Arg.
*/
function myFunctionA(arg) {
return arg;
}
/**
* @param {myTypesB.someType} arg - Arg.
*/
function myFunctionB(arg) {
return arg;
}
export {myFunctionA, myFunctionB};
`,
options: [
{
entryFiles: [],
},
],
parserOptions: {
sourceType: 'module',
},
rules: {
'no-unused-vars': ['error'],
},
},
],
};

0 comments on commit e7694ef

Please sign in to comment.