diff --git a/languages/javascript/language.config.json b/languages/javascript/language.config.json index f9769093..d8d7a62c 100644 --- a/languages/javascript/language.config.json +++ b/languages/javascript/language.config.json @@ -5,6 +5,7 @@ "/index.mjs", "/defaults.mjs" ], + "enableListenAndOnceDeclarations": false, "enableStringPropertyKeys": true, "createModuleDirectories": true, "copySchemasIntoModules": false, diff --git a/languages/markdown/language.config.json b/languages/markdown/language.config.json index 28eebada..cd8eaf48 100644 --- a/languages/markdown/language.config.json +++ b/languages/markdown/language.config.json @@ -3,6 +3,7 @@ "langcode": "markdown", "createModuleDirectories": true, "copySchemasIntoModules": false, + "enableListenAndOnceDeclarations": false, "templatesPerModule": [ "index.md" ], "templatesPerSchema": [ "schemas/index.md" ] } \ No newline at end of file diff --git a/package.json b/package.json index 589b1cba..63f245e5 100644 --- a/package.json +++ b/package.json @@ -14,9 +14,9 @@ "build": "npm run validate && npm run build:docs && npm run build:sdk", "validate": "node ./src/cli.mjs validate --input ./test_sdk/openrpc --platformApi ./build/sdk-open-rpc.json --appApi ./build/sdk-app-open-rpc.json --schemas test_sdk/schemas --transformations && npm run build:openrpc && node ./src/cli.mjs validate --input ./build/sdk-open-rpc.json", "build:openrpc": "node ./src/cli.mjs openrpc --input ./test_sdk --template ./src/openrpc-template.json --platformApi ./build/sdk-open-rpc.json --appApi ./build/sdk-app-open-rpc.json --schemas test_sdk/schemas", - "build:sdk": "node ./src/cli.mjs sdk --input ./build/sdk-open-rpc.json --template ./test_sdk/sdk --output ./build/sdk/javascript/src --platformApi ./build/sdk-open-rpc.json --appApi ./build/sdk-app-open-rpc.json --schemas test_sdk/schemas", + "build:sdk": "node ./src/cli.mjs sdk --input ./build/sdk-open-rpc.json --template ./test_sdk/sdk --config-file-override ./test_sdk/sdk/configOverride/languages/javascript --output ./build/sdk/javascript/src --platformApi ./build/sdk-open-rpc.json --appApi ./build/sdk-app-open-rpc.json --schemas test_sdk/schemas", "build:d": "node ./src/cli.mjs declarations --input ./build/sdk-open-rpc.json --output ./dist/lib/sdk.d.ts --platformApi ./build/sdk-open-rpc.json --appApi ./build/sdk-app-open-rpc.json --schemas test_sdk/schemas", - "build:docs": "node ./src/cli.mjs docs --input ./build/sdk-open-rpc.json --output ./build/docs/markdown --platformApi ./build/sdk-open-rpc.json --appApi ./build/sdk-app-open-rpc.json --schemas test_sdk/schemas --as-path", + "build:docs": "node ./src/cli.mjs docs --input ./build/sdk-open-rpc.json --config-file-override ./test_sdk/sdk/configOverride/languages/markdown --output ./build/docs/markdown --platformApi ./build/sdk-open-rpc.json --appApi ./build/sdk-app-open-rpc.json --schemas test_sdk/schemas --as-path", "build:wiki": "node ./src/cli.mjs docs --input ./build/sdk-open-rpc.json --output ./build/docs/wiki --schemas test_sdk/schemas", "dist": "npm run validate && npm run build:sdk && npm run build:docs && npm run test", "prepare": "husky install" diff --git a/src/cli.mjs b/src/cli.mjs index 36fcbefc..44318bc4 100755 --- a/src/cli.mjs +++ b/src/cli.mjs @@ -20,6 +20,7 @@ const knownOpts = { 'template': [path], 'static-module': [String, Array], 'language': [path], + 'config-file-override': [path], 'examples': [path, Array], 'as-path': [Boolean], 'bidirectional': [Boolean], @@ -48,7 +49,13 @@ const defaults = { // Parse the arguments and merge with the defaults // Ignore args: 0 (node), 1 (cli.mjs), and 2 (the task name, which has no --option in front of it) -const parsedArgs = Object.assign({}, defaults, nopt(knownOpts, shortHands, process.argv, 3)) +const noptResult = nopt(knownOpts, shortHands, process.argv, 3) + +if (noptResult['config-file-override']) { + defaults.config = noptResult['config-file-override'] +} + +const parsedArgs = Object.assign({}, defaults, noptResult) const task = process.argv[2] try { diff --git a/src/docs/index.mjs b/src/docs/index.mjs index 43f1a2dc..4f1bafe8 100755 --- a/src/docs/index.mjs +++ b/src/docs/index.mjs @@ -21,7 +21,7 @@ import path from 'path' import macrofy from '../macrofier/index.mjs' import { readJson } from '../shared/filesystem.mjs' - +import { readConfigFile } from '../shared/configLoader.mjs'; /************************************************************************************************/ /******************************************** MAIN **********************************************/ /************************************************************************************************/ @@ -33,6 +33,7 @@ const run = async ({ output: output, examples: examples, language: language, + config: config, 'as-path': asPath }) => { let libraryName = 'your-library' // TODO find a better default if package.json isn't available... @@ -48,21 +49,23 @@ const run = async ({ // fail silently throw error } - - const config = await readJson(path.join(language, 'language.config.json')) - + // Load in config + const conf = await readConfigFile(config, language); + return macrofy(platformApi, appApi, template, output, { headline: "documentation", outputDirectory: 'content', sharedTemplates: path.join(language, 'templates'), createModuleDirectories: asPath, - copySchemasIntoModules: config.copySchemasIntoModules, + copySchemasIntoModules: conf.copySchemasIntoModules, examples: examples, - templatesPerModule: config.templatesPerModule, - templatesPerSchema: config.templatesPerSchema, - operators: config.operators, + templatesPerModule: conf.templatesPerModule, + templatesPerSchema: conf.templatesPerSchema, + operators: conf.operators, libraryName: libraryName, - hidePrivate: false + hidePrivate: false, + enableListenAndOnceDeclarations: conf.enableListenAndOnceDeclarations || false + }) } diff --git a/src/macrofier/engine.mjs b/src/macrofier/engine.mjs index 2dd0c0b8..90a22e5a 100644 --- a/src/macrofier/engine.mjs +++ b/src/macrofier/engine.mjs @@ -49,6 +49,10 @@ let config = { extractSubSchemas: false, unwrapResultObjects: false, excludeDeclarations: false, + // TODO: This flag is for legacy support. The old behavior was to generate + // listen and once for all components the have events, but after switching to bidirectional + // that is not possible because the event signature is no longer the same for all events - one argument object with all event payload properties + enableListenAndOnceDeclarations: false, } const state = { @@ -635,7 +639,8 @@ const generateMacros = (platformApi, appApi, templates, languages, options = {}) macros.methods.private = methodSection('private-methods', privateMethodsArray) const publicEventsArray = allMethodsArray.filter(m => m.body[dir] && m.event && (!options.hideExcluded || !m.excluded) && !m.private) - const privateEventsArray = allMethodsArray.filter(m => m.body[dir] && m.event && (!options.hideExcluded || !m.excluded && m.private)) + //const privateEventsArray = allMethodsArray.filter(m => m.body[dir] && m.event && (!options.hideExcluded || !m.excluded && m.private)) + const privateEventsArray = [] macros.events.methods = methodSection('events', publicEventsArray) macros.events.private = methodSection('private-events', privateEventsArray) @@ -1347,7 +1352,7 @@ function generateExamples(json = {}, mainTemplates = {}, languages = {}) { return examples } -function generateMethodResult(type, templates) { +function generateMethodResult(type, templates, enableListenAndOnceDeclarations = false) { const result = { name: type, body: {}, @@ -1358,6 +1363,10 @@ function generateMethodResult(type, templates) { const template = getTemplate(('/' + dir + '/' + type), templates) if (template) { if (dir.includes('declarations')) { + //skip listen and once if not enabled" + if (!enableListenAndOnceDeclarations && (type === 'listen' || type === 'once')) { + return; + } result.declaration[dir] = template } else if (dir.includes('methods')) { @@ -1408,8 +1417,17 @@ function generateMethods(platformApi = {}, appApi = null, examples = {}, templat // TODO: might be useful to pass in local macro for an array with all event names if (platformApi.methods && platformApi.methods.find(isPublicEventMethod)) { - ['listen', 'once', 'clear'].forEach(type => { - results.push(generateMethodResult(type, templates)) + + const allEventNames = ['listen', 'once', 'clear']; + + const enableListenAndOnceDeclarations = config.enableListenAndOnceDeclarations || false; + if(!enableListenAndOnceDeclarations && isGeneratingDocs(languages)){ + //remove listen and once for docs generation + allEventNames.splice(0,2); + } + + allEventNames.forEach(type => { + results.push(generateMethodResult(type, templates, enableListenAndOnceDeclarations)) }) } @@ -1655,7 +1673,7 @@ function insertMethodMacros(template, methodObj, platformApi, appApi, templates, } if (isGeneratingDocs(languages)) { - eventNonContextualParams = isEventMethod(methodObj) && event.result ? Types.getMethodSignatureResult(event, currentModuleApiForEvent, { callback: true, namespace: !config.copySchemasIntoModules }) : '' + eventNonContextualParams = isEventMethod(methodObj) && event.result ? Types.getMethodSignatureResult(event, currentModuleApiForEvent, { callback: true, namespace: true}) : '' // If there's a notifier for this method, and it has examples, use its params for the eventParams section if (eventForSubscriber && eventForSubscriber.examples && eventForSubscriber.examples.length) { eventParams = (eventForSubscriber.params && eventForSubscriber.params.length) ? diff --git a/src/macrofier/index.mjs b/src/macrofier/index.mjs index 19a9e032..05e6fbf6 100644 --- a/src/macrofier/index.mjs +++ b/src/macrofier/index.mjs @@ -75,6 +75,7 @@ const macrofy = async ( treeshakePattern = null, treeshakeEntry = null, treeshakeTypes = [], + enableListenAndOnceDeclarations = false, moduleWhitelist = [] } = options @@ -98,6 +99,7 @@ const macrofy = async ( templateExtensionMap, excludeDeclarations, extractProviderSchema, + enableListenAndOnceDeclarations, operators }) diff --git a/src/sdk/index.mjs b/src/sdk/index.mjs index f1df4195..47a7cead 100755 --- a/src/sdk/index.mjs +++ b/src/sdk/index.mjs @@ -21,7 +21,7 @@ import path from 'path' import { readJson } from '../shared/filesystem.mjs' import macrofy from '../macrofier/index.mjs' -import { loadConfig, getConfig } from '../shared/configLoader.mjs'; +import { loadConfig } from '../shared/configLoader.mjs'; /************************************************************************************************/ /******************************************** MAIN **********************************************/ @@ -33,6 +33,7 @@ const run = async ({ template: template, output: output, language: language, + config: config, 'static-module': staticModuleNames, argv: { remain: moduleWhitelist @@ -54,40 +55,40 @@ const run = async ({ } // Load in config - await loadConfig(language) - const config = getConfig() + const conf = await loadConfig(config, language); return macrofy(platformApi, appApi, template, output, { headline: 'SDK code', outputDirectory: 'sdk', sharedTemplates: path.join(language, 'templates'), staticContent: path.join(language, 'src', 'shared'), - templatesPerModule: config.templatesPerModule, - templatesPerSchema: config.templatesPerSchema, - persistPermission: config.persistPermission, - createPolymorphicMethods: config.createPolymorphicMethods || false, - enableUnionTypes: config.enableUnionTypes || false, - operators: config.operators, - primitives: config.primitives, - createModuleDirectories: config.createModuleDirectories, - copySchemasIntoModules: config.copySchemasIntoModules, - extractSubSchemas: config.extractSubSchemas, - convertTuplesToArraysOrObjects: config.convertTuplesToArraysOrObjects, - unwrapResultObjects: config.unwrapResultObjects, - allocatedPrimitiveProxies: config.allocatedPrimitiveProxies, - additionalSchemaTemplates: config.additionalSchemaTemplates, - additionalMethodTemplates: config.additionalMethodTemplates, - templateExtensionMap: config.templateExtensionMap, - excludeDeclarations: config.excludeDeclarations, - extractProviderSchema: config.extractProviderSchema, + templatesPerModule: conf.templatesPerModule, + templatesPerSchema: conf.templatesPerSchema, + persistPermission: conf.persistPermission, + createPolymorphicMethods: conf.createPolymorphicMethods || false, + enableUnionTypes: conf.enableUnionTypes || false, + operators: conf.operators, + primitives: conf.primitives, + createModuleDirectories: conf.createModuleDirectories, + copySchemasIntoModules: conf.copySchemasIntoModules, + extractSubSchemas: conf.extractSubSchemas, + convertTuplesToArraysOrObjects: conf.convertTuplesToArraysOrObjects, + unwrapResultObjects: conf.unwrapResultObjects, + allocatedPrimitiveProxies: conf.allocatedPrimitiveProxies, + additionalSchemaTemplates: conf.additionalSchemaTemplates, + additionalMethodTemplates: conf.additionalMethodTemplates, + templateExtensionMap: conf.templateExtensionMap, + excludeDeclarations: conf.excludeDeclarations, + extractProviderSchema: conf.extractProviderSchema, staticModuleNames: staticModuleNames, hideExcluded: true, moduleWhitelist: moduleWhitelist, - aggregateFiles: config.aggregateFiles, + aggregateFiles: conf.aggregateFiles, rename: mainFilename ? { '/index.mjs': mainFilename, '/index.d.ts': declarationsFilename } : {}, - treeshakePattern: config.treeshakePattern ? new RegExp(config.treeshakePattern, "g") : undefined, - treeshakeTypes: config.treeshakeTypes, - treeshakeEntry: mainFilename ? '/' + mainFilename : '/index.mjs' + treeshakePattern: conf.treeshakePattern ? new RegExp(conf.treeshakePattern, "g") : undefined, + treeshakeTypes: conf.treeshakeTypes, + treeshakeEntry: mainFilename ? '/' + mainFilename : '/index.mjs', + enableListenAndOnceDeclarations: conf.enableListenAndOnceDeclarations || false }) } diff --git a/src/shared/configLoader.mjs b/src/shared/configLoader.mjs index ca9f8fb5..6629b931 100644 --- a/src/shared/configLoader.mjs +++ b/src/shared/configLoader.mjs @@ -1,11 +1,26 @@ import path from 'path' import { readJson } from './filesystem.mjs' +import { logInfo, logSuccess } from './io.mjs' + let config = null -export const loadConfig = async (language) => { +export const readConfigFile = async (customConfig, language) => { + let result = await readJson(path.join(language, 'language.config.json')) + + try { + const overrideConfig = await readJson(path.join(customConfig, 'language.config.json')) + result = { ...result, ...overrideConfig } + logSuccess(`Override default language configuration from ${customConfig}`); + } catch (error) { + logInfo(`Custom language configuration not found at ${customConfig}. Falling back to default configuration.`); + } + return result +} + +export const loadConfig = async (customConfig, language) => { if (!config) { - config = await readJson(path.join(language, 'language.config.json')) + config = await readConfigFile(customConfig, language) } return config }