mirror of
https://github.com/LukeHagar/skeleton.git
synced 2025-12-06 04:21:15 +00:00
Merge pull request #2061 from niktek/bugfix/jsdocs-not-being-inserted-for-all-components
Multi script block handling for jsdocs
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
import { readFileSync, writeFileSync } from 'fs';
|
import { readFileSync, writeFileSync } from 'fs';
|
||||||
|
import { join } from 'path';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import ts from 'typescript';
|
import ts from 'typescript';
|
||||||
|
|
||||||
@@ -14,37 +15,59 @@ function extractScriptsFromComponents(dir) {
|
|||||||
const leadingCharsToStrip = 8; //strip the src/lib/ from the filenames when adding it to the filesToProps mapping
|
const leadingCharsToStrip = 8; //strip the src/lib/ from the filenames when adding it to the filesToProps mapping
|
||||||
const list = fs.readdirSync(dir);
|
const list = fs.readdirSync(dir);
|
||||||
list.forEach((file) => {
|
list.forEach((file) => {
|
||||||
file = dir + '/' + file;
|
file = join(dir, file);
|
||||||
const stat = fs.statSync(file);
|
const stat = fs.statSync(file);
|
||||||
if (stat && stat.isDirectory()) {
|
if (stat && stat.isDirectory()) {
|
||||||
extractScriptsFromComponents(file);
|
extractScriptsFromComponents(file);
|
||||||
} else {
|
} else {
|
||||||
if (file.endsWith('svelte')) {
|
if (file.endsWith('svelte')) {
|
||||||
const src = readFileSync(file).toString();
|
const src = readFileSync(file).toString();
|
||||||
// Split out the script block with lang='ts' section so that we can pass it to the TS compiler
|
const scripts = extractScriptBlocks(src);
|
||||||
// there can be multiple script elements e.g. context='module'
|
|
||||||
const begin = src.indexOf('"ts">\n') + 1;
|
|
||||||
const script = src.substring(begin, src.indexOf('</script>', begin));
|
|
||||||
// the first param is the filename, it is not for reading from the file, but rather for when ts reports issues
|
// the first param is the filename, it is not for reading from the file, but rather for when ts reports issues
|
||||||
// it is also not creating an actual source file, but rather an AST.
|
// it is also not creating an actual source file, but rather an AST.
|
||||||
const node = ts.createSourceFile(file.slice(leadingCharsToStrip), script, ts.ScriptTarget.Latest);
|
const name = file.slice(leadingCharsToStrip);
|
||||||
filesToProps[file.slice(leadingCharsToStrip)] = { node: node };
|
filesToProps[name] = { scriptNodes: [], props: {} };
|
||||||
|
for (const script of scripts) {
|
||||||
|
const node = ts.createSourceFile(name, script, ts.ScriptTarget.Latest);
|
||||||
|
filesToProps[name].scriptNodes.push(node);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
function extractScriptBlocks(content) {
|
||||||
|
let scriptBlocks = [];
|
||||||
|
let startString = '<script';
|
||||||
|
let endString = '</script>';
|
||||||
|
let curPos = 0;
|
||||||
|
while (curPos != -1) {
|
||||||
|
curPos = content.indexOf(startString, curPos);
|
||||||
|
if (curPos == -1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// ignore attributes in script tag
|
||||||
|
curPos = content.indexOf('>', curPos) + 1;
|
||||||
|
let endPos = content.indexOf(endString, curPos);
|
||||||
|
if (endPos == -1) {
|
||||||
|
console.log('Error: missing closing tag for script block');
|
||||||
|
}
|
||||||
|
scriptBlocks.push(content.substring(curPos, endPos));
|
||||||
|
curPos = endPos;
|
||||||
|
}
|
||||||
|
return scriptBlocks;
|
||||||
|
}
|
||||||
|
|
||||||
function extractJSDocBlocks() {
|
function extractJSDocBlocks() {
|
||||||
for (const file in filesToProps) {
|
for (const file in filesToProps) {
|
||||||
let propsObj = {};
|
for (const node of filesToProps[file].scriptNodes) {
|
||||||
_extractJSDocBlocks(filesToProps[file].node, propsObj);
|
_extractJSDocBlocks(file, node);
|
||||||
filesToProps[file].props = propsObj;
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recursive function for traversing node hierarchy to get JSDocs blocks, different node types have the information we want in different places
|
// Recursive function for traversing node hierarchy to get JSDocs blocks, different node types have the information we want in different places
|
||||||
function _extractJSDocBlocks(srcFile, propsObj) {
|
function _extractJSDocBlocks(file, tsNode) {
|
||||||
ts.forEachChild(srcFile, (node) => {
|
ts.forEachChild(tsNode, (node) => {
|
||||||
if (node?.jsDoc) {
|
if (node?.jsDoc) {
|
||||||
// console.log(srcFile);
|
// console.log(srcFile);
|
||||||
const jsDoc = node.jsDoc[node.jsDoc.length - 1];
|
const jsDoc = node.jsDoc[node.jsDoc.length - 1];
|
||||||
@@ -52,23 +75,26 @@ function _extractJSDocBlocks(srcFile, propsObj) {
|
|||||||
switch (node.kind) {
|
switch (node.kind) {
|
||||||
case ts.SyntaxKind.FirstStatement:
|
case ts.SyntaxKind.FirstStatement:
|
||||||
if (declaration.type?.typeName?.escapedText == 'CssClasses') {
|
if (declaration.type?.typeName?.escapedText == 'CssClasses') {
|
||||||
propsObj[declaration.name.escapedText] = { comment: jsDoc.comment, type: 'css' };
|
filesToProps[file].props[declaration.name.escapedText] = { comment: jsDoc.comment, type: 'css' };
|
||||||
} else {
|
} else {
|
||||||
propsObj[declaration.name.escapedText] = { comment: jsDoc.comment, type: 'prop' };
|
filesToProps[file].props[declaration.name.escapedText] = { comment: jsDoc.comment, type: 'prop' };
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ts.SyntaxKind.ExpressionStatement:
|
case ts.SyntaxKind.ExpressionStatement:
|
||||||
propsObj[node.expression.arguments[0].text] = { comment: jsDoc.tags[jsDoc.tags.length - 1].comment ?? '', type: 'event' };
|
filesToProps[file].props[node.expression.arguments[0].text] = {
|
||||||
|
comment: jsDoc.tags[jsDoc.tags.length - 1].comment ?? '',
|
||||||
|
type: 'event'
|
||||||
|
};
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_extractJSDocBlocks(node, propsObj);
|
_extractJSDocBlocks(file, node);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function writeJSDocsToDefinitionFiles() {
|
function writeJSDocsToDefinitionFiles() {
|
||||||
// these two will probably bite us in the ass later on.. but the maximum damage will be no descriptions in intellisense, can live with that.
|
// these two will probably bite us in the ass later on.. but the maximum damage will be no descriptions in intellisense, can live with that.
|
||||||
const propsBegin = 'props: {';
|
const propsBegin = '[x: string]: any;';
|
||||||
const eventsBegin = 'events: {';
|
const eventsBegin = 'events: {';
|
||||||
const blockEnd = '}';
|
const blockEnd = '}';
|
||||||
// we only insert JSDocs for properties that had a JSDoc block declared for them in the component file. Some props that might be defined
|
// we only insert JSDocs for properties that had a JSDoc block declared for them in the component file. Some props that might be defined
|
||||||
@@ -131,6 +157,5 @@ function generateKeyWordsFromProps() {
|
|||||||
extractScriptsFromComponents('src/lib/components');
|
extractScriptsFromComponents('src/lib/components');
|
||||||
extractScriptsFromComponents('src/lib/utilities');
|
extractScriptsFromComponents('src/lib/utilities');
|
||||||
extractJSDocBlocks();
|
extractJSDocBlocks();
|
||||||
extractJSDocBlocks();
|
|
||||||
writeJSDocsToDefinitionFiles();
|
writeJSDocsToDefinitionFiles();
|
||||||
generateKeyWordsFromProps();
|
generateKeyWordsFromProps();
|
||||||
|
|||||||
Reference in New Issue
Block a user