diff --git a/docworks-cli/src/docworks.js b/docworks-cli/src/docworks.js index cfc40cc..ef31084 100755 --- a/docworks-cli/src/docworks.js +++ b/docworks-cli/src/docworks.js @@ -191,8 +191,9 @@ function docworks() { const outputFileName = argv.out const outputDirName = argv.dir || '' const summaryTemplate = argv.summaryTemplate - const ignoredModules = isString_(argv.ignoreModule) ? castArray_(argv.ignoreModule) : [] - const ignoredNamespaces = isString_(argv.ignoreNamespace) ? castArray_(argv.ignoreNamespace) : [] + //todo:: add ignore list + const ignoredModules = isString_(argv.ignoreModule) ? argv.ignoreModule.split(",") : [] + const ignoredNamespaces = isString_(argv.ignoreNamespace) ? argv.ignoreNamespace.split(",") : [] if (!remote && !local || (!!remote && !!local)) { // eslint-disable-next-line no-console diff --git a/docworks-cli/src/run-dts.js b/docworks-cli/src/run-dts.js index 2878424..17e6a5d 100644 --- a/docworks-cli/src/run-dts.js +++ b/docworks-cli/src/run-dts.js @@ -1,5 +1,8 @@ +const isArray_ = require('lodash/isArray') +const isEmpty_ = require('lodash/isEmpty') const path = require('path') const dts = require('docworks-dts') +const { dtsNew } = require('docworks-dts') const logger = require('./logger') const {writeOutput} = require('./utils/fsUtil') const {readRepoFromRemoteOrLocal} = require('./utils/gitUtils') @@ -17,6 +20,13 @@ async function runDts(outputFileName, outputDirName, logger.command('docworks dts', '') const dtsContent = dts(repo.services, {run$wFixer, summaryTemplate, ignoredModules, ignoredNamespaces }) + const dtsNewContent = dtsNew(repo.services, { run$wFixer, summaryTemplate, ignoredModules, ignoredNamespaces }) + // const fileToWrite = ['wix-location', 'wix-window', 'wix-storage', 'wix-site-backend', 'wix-seo', 'wix-realtime', 'wix-paid-plans-backend', 'wix-forum-backend', 'wix-fetch', 'wix-chat-backend', 'wix-captcha-backend'] + dtsNewContent.forEach(file => { + logger.command('writting file', file.name) + // if (fileToWrite.some(f => f=== file.name)) + writeOutput(`${outputDirName}/${file.name}.d.ts`, file.content) + }) const fileNameWithExtensions = `${outputFileName}.d.ts` const fullPath = path.join(outputDirName, fileNameWithExtensions) diff --git a/docworks-dts/lib/dts-converters-new.js b/docworks-dts/lib/dts-converters-new.js new file mode 100644 index 0000000..623aef2 --- /dev/null +++ b/docworks-dts/lib/dts-converters-new.js @@ -0,0 +1,319 @@ +const { validServiceName } = require('./utils') +const isObject_ = require('lodash/isObject') +const isArray_ = require('lodash/isArray') +const isEmpty_ = require('lodash/isEmpty') +const isString_ = require('lodash/isString') +const has_ = require('lodash/has') +const { + dtsConst, + dtsFunction, + dtsFunctionTypeAlias, + dtsInterface, + dtsMethod, + dtsModule, + dtsParameter, + dtsNamespace, + dtsProperty, + dtsObjectTypeAlias +} = require('./dts-generator') + +const fullServiceName = service => + service.memberOf ? `${service.memberOf}.${service.name}` : service.name + +const generateType = (type, parentModuleName) => { + if (type.startsWith(parentModuleName)) { + return type.replace(`${parentModuleName}.`, "") + } + else if (type.includes(`${parentModuleName}.`)) { + const splitedParts = type.split(`${parentModuleName}.`) + return `${parentModuleName}.${splitedParts[splitedParts.length - 1]}` + } + return type +} + +const fixType = (type, parentModuleName) => { + if (parentModuleName) { + if (isString_(type)) { + return generateType(type, parentModuleName) + } + else if(isObject_(type) && has_(type, "name") && (type.name === 'Array' || type.name === 'Promise')) { + type.typeParams = type.typeParams.map(t => { + if (isString_(t)) { + return generateType(t, parentModuleName) + } + console.log("unknow type SECOND IF => ", t) + return t + }) + return type + } + else if (isArray_(type)) { + type = type.map(t => { + if (isString_(t)) { + return generateType(t, parentModuleName) + } + console.log("unknow type THIRD IF => ", t) + return t + }) + return type + } + console.log("START UNFIXED TYPE ", type, " typeof =>" + typeof type," parentModuleName ", parentModuleName, "END") + } + return type +} + +function convertOperationParamToParameters(param, service) { + const { name, type, optional, doc, spread } = param + + const fixedType = fixType(type, service.name) + // console.log("START type => ", type, service.name, fixedType, "END") + return dtsParameter(name, fixedType, { spread, optional, jsDocComment: doc }) +} + +function convertOperationToMethod( + service, + operation, + { documentationGenerator } +) { + const { name, params, ret, docs } = operation + const parameters = params.map(p => convertOperationParamToParameters(p, service)) + const jsDocComment = documentationGenerator({ + summary: docs.summary, + service: fullServiceName(service), + member: name, + eventType: operation.extra && operation.extra.eventType ? operation.extra.eventType : null, + }) + + return dtsMethod(name, parameters, fixType(ret.type, service.name), { jsDocComment }) +} + +function convertPropertyToProperty( + service, + property, + { documentationGenerator } +) { + const readonly = property.get && !property.set + const jsDocComment = documentationGenerator({ + summary: property.docs.summary, + service: fullServiceName(service), + member: property.name + }) + + return dtsProperty(property.name, fixType(property.type, service.name), { readonly, jsDocComment }) +} + +function convertServiceToInterface(service, { documentationGenerator }) { + const properties = service.properties.map(property => + convertPropertyToProperty(service, property, { documentationGenerator }) + ) + const operations = service.operations.map(operation => + convertOperationToMethod(service, operation, { documentationGenerator }) + ) + const members = properties.concat(operations) + const baseTypes = service.mixes.map(validServiceName) + const jsDocComment = documentationGenerator({ + summary: service.docs.summary, + service: fullServiceName(service) + }) + + return dtsInterface(service.name, { members, baseTypes, jsDocComment }) +} + +function convertPropertyToConst(service, property, { documentationGenerator }) { + property.type = fixType(property.type, service.name) + // console.log("type => ", property.type, "END") + const jsDocComment = documentationGenerator({ + summary: property.docs.summary, + service: fullServiceName(service), + member: property.name + }) + return dtsConst(property, { jsDocComment }) +} + +function convertOperationToFunction( + service, + operation, + { documentationGenerator } +) { + const { name, params, ret, docs } = operation + const parameters = params.map(p => convertOperationParamToParameters(p, service)) + const jsDocComment = documentationGenerator({ + summary: docs.summary, + service: fullServiceName(service), + member: name + }) + + return dtsFunction(name, parameters, fixType(ret.type, service.name), { jsDocComment }) +} + + +function convertMessageMemberToProperty(member, service) { + const { name, type, optional, doc } = member + const fixedType = fixType(type, service.name) + // console.log("type => ", type, "END") + return dtsProperty(name, fixedType, { optional, jsDocComment: doc }) +} + +function convertMessageToObjectType(message, service) { + const jsDocComment = message.docs.summary + const properties = message.members ? message.members.map(m => convertMessageMemberToProperty(m, service)): [] + + return dtsObjectTypeAlias(message.name, properties, { jsDocComment }) +} + +function convertCallbackToFunctionType(callback, service) { + const { name, params = [], ret, docs } = callback + const fixedType = fixType(ret.type, service.name) + // console.log("type => ", ret.type, "END") + const parameters = params.map( p => convertOperationParamToParameters(p, service)) + const jsDocComment = docs.summary + + return dtsFunctionTypeAlias(name, parameters, fixedType, { jsDocComment }) +} + +function extractDataFromService(service, documentationGenerator) { + const properties = service.properties.map(property => + convertPropertyToConst(service, property, { documentationGenerator }) + ) + const operations = service.operations.map(operation => + convertOperationToFunction(service, operation, { documentationGenerator }) + ) + + const types = [] + service.messages.forEach(message => { + const type = convertMessageToObjectType(message, service) + types.push(type) + }) + + const callbacks = [] + service.callbacks.forEach(callback => { + const type = convertCallbackToFunctionType(callback, service) + callbacks.push(type) + }) + return properties.concat(operations).concat(types).concat(callbacks) +} + +function convertMessageToType(service, message) { + const jsDocComment = message.docs.summary + const properties = message.members.map(p => convertMessageMemberToProperty(p, service)) + + return dtsObjectTypeAlias(message.name, properties, { jsDocComment }) +} + +function convertCallbackToType(service, callback) { + const { name, params, ret, docs } = callback + const parameters = params.map(p => convertOperationParamToParameters(p, service)) + const jsDocComment = docs.summary + + return dtsFunctionTypeAlias(name, parameters, fixType(ret.type, service.name), { jsDocComment }) +} + +function covert$wServiceToNamespace() {} + +function convertServiceToNamespace( + service, + parentService, + { documentationGenerator } = {} +) { + //TODO:: need to handle service.sub.sub etc... + // service.memberOf = parentService.name + const serviceName = service.name + const namespace = dtsNamespace(serviceName) + if (service.name === "TimeLine")debugger + // here need to say this is the root module of the inteface parentService + const intf = convertServiceToInterface(service, { documentationGenerator }) + namespace.members.push(intf) + + const messages = service.messages + const callbacks = service.callbacks + const sub = service.sub + Object.keys(sub).forEach(subKey => { + + const subModule = sub[subKey] + console.log("SUB >> ", subKey, "$$$$", subModule.memberOf) + const subModuleInterface = convertServiceToInterface(subModule, { documentationGenerator }) + namespace.members.push(subModuleInterface) + }) + if (messages.length > 0 || callbacks.length > 0) { + const innerNamespace = dtsNamespace(serviceName) + + messages.forEach(message => { + const type = convertMessageToType(service, message) + innerNamespace.members.push(type) + }) + + callbacks.forEach(callback => { + const type = convertCallbackToType(service, callback) + innerNamespace.members.push(type) + }) + + + namespace.members.push(innerNamespace) + } + return namespace +} + +function convertServiceToNamespaceRecursivly({ service, namespace = dtsNamespace(service.name), documentationGenerator } = {}) { + if(!has_(service, "sub")) { + return namespace + } + else { + // the interface of the service should be at root module level + debugger + // all messages, callbacks, sub (should be inner namespace) + const messages = service.messages + const callbacks = service.callbacks + if (messages.length > 0 || callbacks.length > 0) { + messages.forEach(message => { + const type = convertMessageToType(service, message) + namespace.members.push(type) + }) + + callbacks.forEach(callback => { + const type = convertCallbackToType(service, callback) + namespace.members.push(type) + }) + } + const { sub } = service + Object.keys(sub).forEach(subKey => { + namespace.members.push(convertServiceToNamespaceRecursivly({ service: sub[subKey], namespace, documentationGenerator })) + }) + return namespace + } +} + +function convertServiceToModule(service, sub, { documentationGenerator }) { + + let subSections = [] + Object.keys(sub).forEach(subKey => { + const subSection = sub[subKey] + if (subSection.memberOf !== '$w') { + console.log(" NAME ", subSection.name) + // if (subSection.name === 'WixBookingsQueryResult') { + // debugger + // } + // const namespace1 = convertServiceToNamespaceRecursivly({service: subSection, documentationGenerator }) + // const intf = convertServiceToInterface(service, { documentationGenerator }) + // subSections.push(intf) + const namespace = convertServiceToNamespace(subSection, service, { documentationGenerator }) + subSections = subSections.concat(namespace.members) + } + else { + // TODO:: handle $w + } + }) + + const members = extractDataFromService(service, documentationGenerator) + .concat(subSections) + + const jsDocComment = documentationGenerator({ + summary: service.docs.summary, + service: fullServiceName(service) + }) + + return dtsModule(service.name, { members, jsDocComment }) +} + +module.exports = { + convertServiceToModule, + covert$wServiceToNamespace +} diff --git a/docworks-dts/lib/dts-repo-new.js b/docworks-dts/lib/dts-repo-new.js new file mode 100644 index 0000000..1ba0970 --- /dev/null +++ b/docworks-dts/lib/dts-repo-new.js @@ -0,0 +1,94 @@ +const template_ = require('lodash/template') +const $wFixer = require('./$w-fixer') +const { convertTreeToString, dtsNamespace } = require('./dts-generator') +const { + convertServiceToModule +} = require('./dts-converters-new') +const get_ = require("lodash/get") +const has_ = require("lodash/has") + + +function createModule(rootModule, { documentationGenerator }) { + // todo:: if $w need to do somthing else (aka skip the operations and declare namespace insted of module) + const service = rootModule + const sub = rootModule.sub + const module = convertServiceToModule(service, sub, { documentationGenerator }) + return { name: service.name, content: convertTreeToString({ module }) } +} + +function dts( + services, + { run$wFixer = false, summaryTemplate, ignoredModules = [], ignoredNamespaces = [] } = {} +) { + const namespaces = {} + const modules = {} + let documentationGenerator = ({summary}) => summary + + if (summaryTemplate) { + documentationGenerator = values => { + return template_(summaryTemplate)({model: values}) + } + } + + const rootServices = {} + const subServices = [] + + services.forEach(service => { + service.wasHere = 0 + if (!service.memberOf) { + rootServices[service.name] = {...service, sub: {}} + } else { + subServices.push(service) + } + }) + + while (subServices.length > 0) { + const service = subServices.shift() + if (!service.memberOf.includes (".")) { + if (has_(rootServices, service.memberOf)) { + // console.log("SUB >> ", service.name, " memberOf>> ", service.memberOf) + Object.assign(rootServices[service.memberOf].sub, { [service.name] : {...service, sub: {}} }) + } + else { + // console.log("SHOULD NOT BE HERE ", service.name, " >> ", service.memberOf) + subServices.push(service) + } + } + else if (service.wasHere < 3) { + const parentTypeParts = service.memberOf.split(".").join('.sub.') + if (has_(rootServices, parentTypeParts)) { + // console.log("SETTING INNER >> ", service.name, " memberOf>> ", service.memberOf) + const directParent = get_(rootServices, parentTypeParts) + const targetSub = Object.assign({}, directParent.sub, { [service.name] : {...service, sub: {}}}) + directParent.sub = targetSub + } + else { + // console.log(" PATH DOES NOT EXSISTS FIRST TIME >> ", parentTypeParts, " >> ", service.name) + service.wasHere++ + subServices.push(service) + } + } + else { + throw Error("UNKNOW MODULE " + service.name) + } + } + + const generatedModules = [] + Object.keys(rootServices).forEach(root => { + generatedModules.push(createModule(rootServices[root], { documentationGenerator })) + }) + + debugger + // remove ignored modules and namespaces from output + ignoredNamespaces.forEach(namespace => delete namespaces[namespace]) + ignoredModules.forEach(module => delete modules[module]) + ignoredModules.forEach(module => delete generatedModules[module]) + + if (run$wFixer) { + $wFixer(modules, namespaces) + } + + return generatedModules +} + +module.exports = dts diff --git a/docworks-dts/lib/dts-repo.js b/docworks-dts/lib/dts-repo.js index 343835e..ef265b7 100644 --- a/docworks-dts/lib/dts-repo.js +++ b/docworks-dts/lib/dts-repo.js @@ -82,6 +82,27 @@ function handleServiceAsNamespace( } } +function handleSubServices(service, parent) { + const serviceName = service.name + const messages = service.messages + const callbacks = service.callbacks + console.log("^^^^^^^^^^^^^^^^^^^^^", "serviceName => ", serviceName, "^^^^^^^^^^^^^^^^^^^^^") + console.log("^^^^^^^^^^^^^^^^^^^^^", "messages => ", messages.map(m => `${parent}.${serviceName}.${m.name}`), "^^^^^^^^^^^^^^^^^^^^^") + console.log("^^^^^^^^^^^^^^^^^^^^^", "callbacks => ", callbacks.map(c => `${parent}.${serviceName}.${c.name}`), "^^^^^^^^^^^^^^^^^^^^^") + console.log("*********************", "SUB END", "*********************") +} + +function handleRootServices(service) { + const serviceName = service.name + const messages = service.messages + const callbacks = service.callbacks + console.log("*********************", "ROOT START", "*********************") + console.log("^^^^^^^^^^^^^^^^^^^^^", "serviceName => ", serviceName, "^^^^^^^^^^^^^^^^^^^^^") + console.log("^^^^^^^^^^^^^^^^^^^^^", "messages => ", messages.map(m => `${serviceName}.${m.name}`), "^^^^^^^^^^^^^^^^^^^^^") + console.log("^^^^^^^^^^^^^^^^^^^^^", "callbacks => ", callbacks.map(c => `${serviceName}.${c.name}`), "^^^^^^^^^^^^^^^^^^^^^") + console.log("*********************", "ROOT END", "*********************") +} + function dts( services, { run$wFixer = false, summaryTemplate, ignoredModules = [], ignoredNamespaces = [] } = {} @@ -96,16 +117,36 @@ function dts( } } + const rootServices = {} + const subServices = [] + services.forEach(service => { if (!service.memberOf) { + // handleRootServices(service) + rootServices[service.name] = {instance: service, sub: {}} handleServiceAsModule(service, modules, namespaces, {documentationGenerator}) } else { + // handleSubServices(service, service.memberOf) + subServices.push(service) handleServiceAsNamespace(service, namespaces, {documentationGenerator}) } }) + subServices.forEach(sub => { + if(rootServices[sub.memberOf]) { + Object.assign(rootServices[sub.memberOf].sub, {[sub.name] : sub}) + } + }) + // console.log("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&") + // Object.keys(rootServices).forEach(root => { + // Object.keys(rootServices[root].sub).forEach(s => { + // console.log(`${root}.${s}`) + // }) + // }) + // console.log("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&") // remove ignored modules and namespaces from output + debugger ignoredNamespaces.forEach(namespace => delete namespaces[namespace]) ignoredModules.forEach(module => delete modules[module]) diff --git a/docworks-dts/lib/index.js b/docworks-dts/lib/index.js index a175450..f6219ea 100644 --- a/docworks-dts/lib/index.js +++ b/docworks-dts/lib/index.js @@ -1,9 +1,11 @@ 'use strict' const dts = require('./dts-repo') +const dtsNew = require('./dts-repo-new') const docworksToDtsConverters = require('./dts-converters') const dtsGenerator = require('./dts-generator') module.exports = dts +module.exports.dtsNew = dtsNew module.exports.docworksToDtsConverters = docworksToDtsConverters module.exports.dtsGenerator = dtsGenerator