@wc-toolkit/jsdoc-tags
Version:
A set of tools for retrieving and transforming data from the Custom Elements Manifest
537 lines (519 loc) • 17.2 kB
JavaScript
;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var index_exports = {};
__export(index_exports, {
jsDocTagsPlugin: () => jsDocTagsPlugin,
parseJsDocTags: () => parseJsDocTags
});
module.exports = __toCommonJS(index_exports);
// node_modules/.pnpm/comment-parser@1.4.1/node_modules/comment-parser/es6/primitives.js
var Markers;
(function(Markers2) {
Markers2["start"] = "/**";
Markers2["nostart"] = "/***";
Markers2["delim"] = "*";
Markers2["end"] = "*/";
})(Markers = Markers || (Markers = {}));
// node_modules/.pnpm/comment-parser@1.4.1/node_modules/comment-parser/es6/util.js
function isSpace(source) {
return /^\s+$/.test(source);
}
function splitCR(source) {
const matches = source.match(/\r+$/);
return matches == null ? ["", source] : [source.slice(-matches[0].length), source.slice(0, -matches[0].length)];
}
function splitSpace(source) {
const matches = source.match(/^\s+/);
return matches == null ? ["", source] : [source.slice(0, matches[0].length), source.slice(matches[0].length)];
}
function splitLines(source) {
return source.split(/\n/);
}
function seedSpec(spec = {}) {
return Object.assign({ tag: "", name: "", type: "", optional: false, description: "", problems: [], source: [] }, spec);
}
function seedTokens(tokens = {}) {
return Object.assign({ start: "", delimiter: "", postDelimiter: "", tag: "", postTag: "", name: "", postName: "", type: "", postType: "", description: "", end: "", lineEnd: "" }, tokens);
}
// node_modules/.pnpm/comment-parser@1.4.1/node_modules/comment-parser/es6/parser/block-parser.js
var reTag = /^@\S+/;
function getParser({ fence = "```" } = {}) {
const fencer = getFencer(fence);
const toggleFence = (source, isFenced) => fencer(source) ? !isFenced : isFenced;
return function parseBlock(source) {
const sections = [[]];
let isFenced = false;
for (const line of source) {
if (reTag.test(line.tokens.description) && !isFenced) {
sections.push([line]);
} else {
sections[sections.length - 1].push(line);
}
isFenced = toggleFence(line.tokens.description, isFenced);
}
return sections;
};
}
function getFencer(fence) {
if (typeof fence === "string")
return (source) => source.split(fence).length % 2 === 0;
return fence;
}
// node_modules/.pnpm/comment-parser@1.4.1/node_modules/comment-parser/es6/parser/source-parser.js
function getParser2({ startLine = 0, markers = Markers } = {}) {
let block = null;
let num = startLine;
return function parseSource(source) {
let rest = source;
const tokens = seedTokens();
[tokens.lineEnd, rest] = splitCR(rest);
[tokens.start, rest] = splitSpace(rest);
if (block === null && rest.startsWith(markers.start) && !rest.startsWith(markers.nostart)) {
block = [];
tokens.delimiter = rest.slice(0, markers.start.length);
rest = rest.slice(markers.start.length);
[tokens.postDelimiter, rest] = splitSpace(rest);
}
if (block === null) {
num++;
return null;
}
const isClosed = rest.trimRight().endsWith(markers.end);
if (tokens.delimiter === "" && rest.startsWith(markers.delim) && !rest.startsWith(markers.end)) {
tokens.delimiter = markers.delim;
rest = rest.slice(markers.delim.length);
[tokens.postDelimiter, rest] = splitSpace(rest);
}
if (isClosed) {
const trimmed = rest.trimRight();
tokens.end = rest.slice(trimmed.length - markers.end.length);
rest = trimmed.slice(0, -markers.end.length);
}
tokens.description = rest;
block.push({ number: num, source, tokens });
num++;
if (isClosed) {
const result = block.slice();
block = null;
return result;
}
return null;
};
}
// node_modules/.pnpm/comment-parser@1.4.1/node_modules/comment-parser/es6/parser/spec-parser.js
function getParser3({ tokenizers }) {
return function parseSpec(source) {
var _a;
let spec = seedSpec({ source });
for (const tokenize of tokenizers) {
spec = tokenize(spec);
if ((_a = spec.problems[spec.problems.length - 1]) === null || _a === void 0 ? void 0 : _a.critical)
break;
}
return spec;
};
}
// node_modules/.pnpm/comment-parser@1.4.1/node_modules/comment-parser/es6/parser/tokenizers/tag.js
function tagTokenizer() {
return (spec) => {
const { tokens } = spec.source[0];
const match = tokens.description.match(/\s*(@(\S+))(\s*)/);
if (match === null) {
spec.problems.push({
code: "spec:tag:prefix",
message: 'tag should start with "@" symbol',
line: spec.source[0].number,
critical: true
});
return spec;
}
tokens.tag = match[1];
tokens.postTag = match[3];
tokens.description = tokens.description.slice(match[0].length);
spec.tag = match[2];
return spec;
};
}
// node_modules/.pnpm/comment-parser@1.4.1/node_modules/comment-parser/es6/parser/tokenizers/type.js
function typeTokenizer(spacing = "compact") {
const join2 = getJoiner(spacing);
return (spec) => {
let curlies = 0;
let lines = [];
for (const [i, { tokens }] of spec.source.entries()) {
let type = "";
if (i === 0 && tokens.description[0] !== "{")
return spec;
for (const ch of tokens.description) {
if (ch === "{")
curlies++;
if (ch === "}")
curlies--;
type += ch;
if (curlies === 0)
break;
}
lines.push([tokens, type]);
if (curlies === 0)
break;
}
if (curlies !== 0) {
spec.problems.push({
code: "spec:type:unpaired-curlies",
message: "unpaired curlies",
line: spec.source[0].number,
critical: true
});
return spec;
}
const parts = [];
const offset = lines[0][0].postDelimiter.length;
for (const [i, [tokens, type]] of lines.entries()) {
tokens.type = type;
if (i > 0) {
tokens.type = tokens.postDelimiter.slice(offset) + type;
tokens.postDelimiter = tokens.postDelimiter.slice(0, offset);
}
[tokens.postType, tokens.description] = splitSpace(tokens.description.slice(type.length));
parts.push(tokens.type);
}
parts[0] = parts[0].slice(1);
parts[parts.length - 1] = parts[parts.length - 1].slice(0, -1);
spec.type = join2(parts);
return spec;
};
}
var trim = (x) => x.trim();
function getJoiner(spacing) {
if (spacing === "compact")
return (t) => t.map(trim).join("");
else if (spacing === "preserve")
return (t) => t.join("\n");
else
return spacing;
}
// node_modules/.pnpm/comment-parser@1.4.1/node_modules/comment-parser/es6/parser/tokenizers/name.js
var isQuoted = (s) => s && s.startsWith('"') && s.endsWith('"');
function nameTokenizer() {
const typeEnd = (num, { tokens }, i) => tokens.type === "" ? num : i;
return (spec) => {
const { tokens } = spec.source[spec.source.reduce(typeEnd, 0)];
const source = tokens.description.trimLeft();
const quotedGroups = source.split('"');
if (quotedGroups.length > 1 && quotedGroups[0] === "" && quotedGroups.length % 2 === 1) {
spec.name = quotedGroups[1];
tokens.name = `"${quotedGroups[1]}"`;
[tokens.postName, tokens.description] = splitSpace(source.slice(tokens.name.length));
return spec;
}
let brackets = 0;
let name = "";
let optional = false;
let defaultValue;
for (const ch of source) {
if (brackets === 0 && isSpace(ch))
break;
if (ch === "[")
brackets++;
if (ch === "]")
brackets--;
name += ch;
}
if (brackets !== 0) {
spec.problems.push({
code: "spec:name:unpaired-brackets",
message: "unpaired brackets",
line: spec.source[0].number,
critical: true
});
return spec;
}
const nameToken = name;
if (name[0] === "[" && name[name.length - 1] === "]") {
optional = true;
name = name.slice(1, -1);
const parts = name.split("=");
name = parts[0].trim();
if (parts[1] !== void 0)
defaultValue = parts.slice(1).join("=").trim();
if (name === "") {
spec.problems.push({
code: "spec:name:empty-name",
message: "empty name",
line: spec.source[0].number,
critical: true
});
return spec;
}
if (defaultValue === "") {
spec.problems.push({
code: "spec:name:empty-default",
message: "empty default value",
line: spec.source[0].number,
critical: true
});
return spec;
}
if (!isQuoted(defaultValue) && /=(?!>)/.test(defaultValue)) {
spec.problems.push({
code: "spec:name:invalid-default",
message: "invalid default value syntax",
line: spec.source[0].number,
critical: true
});
return spec;
}
}
spec.optional = optional;
spec.name = name;
tokens.name = nameToken;
if (defaultValue !== void 0)
spec.default = defaultValue;
[tokens.postName, tokens.description] = splitSpace(source.slice(tokens.name.length));
return spec;
};
}
// node_modules/.pnpm/comment-parser@1.4.1/node_modules/comment-parser/es6/parser/tokenizers/description.js
function descriptionTokenizer(spacing = "compact", markers = Markers) {
const join2 = getJoiner2(spacing);
return (spec) => {
spec.description = join2(spec.source, markers);
return spec;
};
}
function getJoiner2(spacing) {
if (spacing === "compact")
return compactJoiner;
if (spacing === "preserve")
return preserveJoiner;
return spacing;
}
function compactJoiner(lines, markers = Markers) {
return lines.map(({ tokens: { description } }) => description.trim()).filter((description) => description !== "").join(" ");
}
var lineNo = (num, { tokens }, i) => tokens.type === "" ? num : i;
var getDescription = ({ tokens }) => (tokens.delimiter === "" ? tokens.start : tokens.postDelimiter.slice(1)) + tokens.description;
function preserveJoiner(lines, markers = Markers) {
if (lines.length === 0)
return "";
if (lines[0].tokens.description === "" && lines[0].tokens.delimiter === markers.start)
lines = lines.slice(1);
const lastLine = lines[lines.length - 1];
if (lastLine !== void 0 && lastLine.tokens.description === "" && lastLine.tokens.end.endsWith(markers.end))
lines = lines.slice(0, -1);
lines = lines.slice(lines.reduce(lineNo, 0));
return lines.map(getDescription).join("\n");
}
// node_modules/.pnpm/comment-parser@1.4.1/node_modules/comment-parser/es6/parser/index.js
function getParser4({ startLine = 0, fence = "```", spacing = "compact", markers = Markers, tokenizers = [
tagTokenizer(),
typeTokenizer(spacing),
nameTokenizer(),
descriptionTokenizer(spacing)
] } = {}) {
if (startLine < 0 || startLine % 1 > 0)
throw new Error("Invalid startLine");
const parseSource = getParser2({ startLine, markers });
const parseBlock = getParser({ fence });
const parseSpec = getParser3({ tokenizers });
const joinDescription = getJoiner2(spacing);
return function(source) {
const blocks = [];
for (const line of splitLines(source)) {
const lines = parseSource(line);
if (lines === null)
continue;
const sections = parseBlock(lines);
const specs = sections.slice(1).map(parseSpec);
blocks.push({
description: joinDescription(sections[0], markers),
tags: specs,
source: lines,
problems: specs.reduce((acc, spec) => acc.concat(spec.problems), [])
});
}
return blocks;
};
}
// node_modules/.pnpm/comment-parser@1.4.1/node_modules/comment-parser/es6/stringifier/index.js
function join(tokens) {
return tokens.start + tokens.delimiter + tokens.postDelimiter + tokens.tag + tokens.postTag + tokens.type + tokens.postType + tokens.name + tokens.postName + tokens.description + tokens.end + tokens.lineEnd;
}
function getStringifier() {
return (block) => block.source.map(({ tokens }) => join(tokens)).join("\n");
}
// node_modules/.pnpm/comment-parser@1.4.1/node_modules/comment-parser/es6/stringifier/inspect.js
var zeroWidth = {
line: 0,
start: 0,
delimiter: 0,
postDelimiter: 0,
tag: 0,
postTag: 0,
name: 0,
postName: 0,
type: 0,
postType: 0,
description: 0,
end: 0,
lineEnd: 0
};
var fields = Object.keys(zeroWidth);
// node_modules/.pnpm/comment-parser@1.4.1/node_modules/comment-parser/es6/index.js
function parse(source, options = {}) {
return getParser4(options)(source);
}
var stringify = getStringifier();
// src/logger.ts
var Logger = class {
#debug;
constructor(debug = false) {
this.#debug = debug;
}
log(message, color = "\x1B[30m%s\x1B[0m") {
if (!this.#debug) {
return;
}
console.log(color, message);
}
red(message) {
this.log(message, "\x1B[31m%s\x1B[0m");
}
green(message) {
this.log(message, "\x1B[32m%s\x1B[0m");
}
yellow(message) {
this.log(message, "\x1B[33m%s\x1B[0m");
}
blue(message) {
this.log(message, "\x1B[34m%s\x1B[0m");
}
magenta(message) {
this.log(message, "\x1B[35m%s\x1B[0m");
}
cyan(message) {
this.log(message, "\x1B[36m%s\x1B[0m");
}
};
// node_modules/.pnpm/@wc-toolkit+cem-utilities@1.0.0/node_modules/@wc-toolkit/cem-utilities/dist/index.js
function deepMerge(target, source) {
if (typeof target !== "object" || target === null) {
return source;
}
if (typeof source !== "object" || source === null) {
return target;
}
const targetObj = target;
const sourceObj = source;
for (const key of Object.keys(source)) {
if (sourceObj[key] instanceof Array) {
if (!targetObj[key]) {
targetObj[key] = [];
}
targetObj[key] = targetObj[key].concat(sourceObj[key]);
} else if (sourceObj[key] instanceof Object) {
if (!targetObj[key]) {
targetObj[key] = {};
}
targetObj[key] = deepMerge(targetObj[key], sourceObj[key]);
} else {
targetObj[key] = sourceObj[key];
}
}
return targetObj;
}
// src/cem-plugin.ts
var userOptions = {
tags: {}
};
function jsDocTagsPlugin(options = {}) {
userOptions = deepMerge(userOptions, options);
const log = new Logger(userOptions.debug);
if (options.skip) {
log.yellow("[jsdoc-tags] - Skipped");
return;
}
log.log("[jsdoc-tags] - Updating Custom Elements Manifest...");
return {
name: "jsdoc-tags-plugin",
analyzePhase(params) {
parseJsDocTags(params, userOptions.tags || {});
},
packageLinkPhase: () => {
log.green("[cem-expanded-types] - Custom Elements Manifest updated.");
}
};
}
function parseJsDocTags(params, tags) {
if (params.node.kind !== params.ts.SyntaxKind.ClassDeclaration) {
return;
}
const className = params.node.name.getText();
const component = params.moduleDoc?.declarations?.find(
(declaration) => declaration.name === className
);
const customTags = Object.keys(tags || {});
let customComments = "/**";
params.node.jsDoc?.forEach((jsDoc) => {
jsDoc?.tags?.forEach(
(tag) => {
const tagName = tag.tagName.getText();
if (customTags.includes(tagName)) {
customComments += `
* @${tagName} ${tag.comment}`;
}
}
);
});
const parsed = parse(`${customComments}
*/`);
parsed[0]?.tags?.forEach((tagMeta) => {
const tagOptions = tags[tagMeta.tag];
if (!tagOptions) {
return;
}
const propName = tagOptions.mappedName || tagMeta.tag;
if (!component) {
return;
}
const existingProp = component[propName];
const cemTag = {
name: tagMeta.name === "-" ? "" : tagMeta.name,
default: tagMeta.default,
description: tagMeta.description.replace(/^\s?-/, "").trim(),
// removes leading dash
type: tagMeta.type ? { text: tagMeta.type } : void 0
};
if (!existingProp && tagOptions.isArray) {
component[propName] = [cemTag];
} else if (Array.isArray(component[propName])) {
component[propName].push(cemTag);
} else if (existingProp && !Array.isArray(component[propName])) {
component[propName] = [component[propName], cemTag];
} else {
component[propName] = cemTag;
}
});
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
jsDocTagsPlugin,
parseJsDocTags
});