Skip to content

Commit

Permalink
fixup! preserve backwards compat for lb4 repository
Browse files Browse the repository at this point in the history
Signed-off-by: Miroslav Bajtoš <[email protected]>
  • Loading branch information
bajtos committed Apr 6, 2020
1 parent 203a1b4 commit eb5774b
Show file tree
Hide file tree
Showing 7 changed files with 235 additions and 76 deletions.
5 changes: 3 additions & 2 deletions packages/cli/generators/datasource/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -191,8 +191,9 @@ module.exports = class DataSourceGenerator extends ArtifactGenerator {
break;
default:
console.warn(
`Using default input of type input for setting ${key} as ${setting.type ||
undefined} is not supported`,
`Using default input of type input for setting ${key} as ${
setting.type || undefined
} is not supported`,
);
// Default to input type
question.type = 'input';
Expand Down
14 changes: 11 additions & 3 deletions packages/cli/generators/repository/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ module.exports = class RepositoryGenerator extends ArtifactGenerator {
? utils.toClassName(this.options.datasource) + 'Datasource'
: '';

debug(`command line datasource is ${cmdDatasourceName}`);
debug('command line datasource is %j', cmdDatasourceName);

try {
datasourcesList = await utils.getArtifactList(
Expand All @@ -251,19 +251,27 @@ module.exports = class RepositoryGenerator extends ArtifactGenerator {
true,
);
debug(
`datasourcesList from ${utils.sourceRootDir}/${utils.datasourcesDir} : ${datasourcesList}`,
'datasourcesList from %s/%s:',
utils.sourceRootDir,
utils.datasourcesDir,
datasourcesList,
);
} catch (err) {
return this.exit(err);
}

const availableDatasources = datasourcesList.filter(item => {
debug(`data source inspecting item: ${item}`);
const result = utils.isConnectorOfType(
VALID_CONNECTORS_FOR_REPOSITORY,
this.artifactInfo.datasourcesDir,
item,
);
debug(
'has %s connector of type %o? %s',
item,
VALID_CONNECTORS_FOR_REPOSITORY,
result,
);
return result !== false;
});

Expand Down
77 changes: 74 additions & 3 deletions packages/cli/lib/ast-helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ const debug = require('./debug')('ast-query');
*/
exports.getIdFromModel = function (fileContent) {
const ast = tsquery.ast(fileContent);
for (const queryName in QUERIES) {
for (const queryName in MODEL_ID_QUERIES) {
debug('Trying %s', queryName);
const {query, getModelPropertyDeclaration} = QUERIES[queryName];
const {query, getModelPropertyDeclaration} = MODEL_ID_QUERIES[queryName];

const idFieldAssignments = tsquery(ast, query);

Expand Down Expand Up @@ -58,7 +58,7 @@ exports.getIdFromModel = function (fileContent) {
}
};

const QUERIES = {
const MODEL_ID_QUERIES = {
'default format generated by lb4 model': {
// @property({id: true|1})
// id: number
Expand Down Expand Up @@ -141,3 +141,74 @@ function isPrimaryKeyFlag(idInitializer) {

return false;
}

exports.getDataSourceConfig = function (fileContent) {
const ast = tsquery.ast(fileContent);
// Find a top-level declaration of `config` variable
const configVarDecl = tsquery(
ast,
// It must be a top-level declaration, not inside a function
'SourceFile>VariableStatement>VariableDeclarationList>' +
// The declaration should be for property called `config`
'VariableDeclaration:has([name="config"])',
);
if (!configVarDecl || configVarDecl.length < 1) {
debug('No top-level declaration of variable "config" was not found.');
return undefined;
}

const initializer = configVarDecl[0].initializer;
const initializerKindName = syntaxKindName(initializer.kind);
if (initializerKindName !== 'ObjectLiteralExpression') {
debug(
'Variable "config" is declare with an unsupported initializer kind %s.',
initializerKindName,
);
return undefined;
}

const config = Object.create(null);
for (const prop of initializer.properties) {
const propKind = syntaxKindName(prop.kind);
if (propKind !== 'PropertyAssignment') {
debug('Skipping unknown property kind %s', propKind);
continue;
}

const propNameKind = syntaxKindName(prop.name.kind);
if (propNameKind !== 'Identifier') {
debug('Skipping unknown property name kind %s', propNameKind);
continue;
}

const propName = prop.name.escapedText;

const propInitKind = syntaxKindName(prop.initializer.kind);
let propValue;
switch (propInitKind) {
case 'StringLiteral':
propValue = prop.initializer.text;
break;
case 'NumericLiteral':
propValue = +prop.initializer.text;
break;
case 'TrueLiteral':
propValue = true;
break;
case 'FalseLiteral':
propValue = false;
break;
default:
debug(
'Skipping unsupported property initializer kind %s',
propInitKind,
);
continue;
}

debug('Adding config entry %s: %j', propName, propValue);
config[propName] = propValue;
}

return config;
};
91 changes: 54 additions & 37 deletions packages/cli/lib/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const urlSlug = require('url-slug');
const validate = require('validate-npm-package-name');
const Conflicter = require('yeoman-generator/lib/util/conflicter');
const connectors = require('./connectors.json');
const tsquery = require('./ast-helper');
const stringifyObject = require('stringify-object');
const camelCase = _.camelCase;
const kebabCase = _.kebabCase;
Expand Down Expand Up @@ -287,7 +288,7 @@ exports.StatusConflicter = class StatusConflicter extends Conflicter {
*/
exports.findArtifactPaths = async function (dir, artifactType, reader) {
const readdir = reader || readdirAsync;
debug(`Finding artifact paths at: ${dir}`);
debug('Finding %j artifact paths at %s', artifactType, dir);

try {
// Wrapping readdir in case it's not a promise.
Expand Down Expand Up @@ -323,7 +324,7 @@ exports.getArtifactList = async function (
reader,
) {
const paths = await exports.findArtifactPaths(dir, artifactType, reader);
debug(`Filtering artifact paths: ${paths}`);
debug('Artifacts paths found:', paths);
return paths.map(p => {
const firstWord = _.first(_.split(_.last(_.split(p, path.sep)), '.'));
const result = pascalCase(exports.toClassName(firstWord));
Expand Down Expand Up @@ -581,31 +582,18 @@ exports.isConnectorOfType = function (
datasourcesDir,
dataSourceClass,
) {
debug(`calling isConnectorType ${connectorType}`);
let jsonFileContent = '';
debug('calling isConnectorType %o for %s', connectorType, dataSourceClass);

if (!dataSourceClass) {
return false;
}

const datasourceJSONFile = path.join(
datasourcesDir,
exports.dataSourceToJSONFileName(dataSourceClass),
);

debug(`reading ${datasourceJSONFile}`);
try {
jsonFileContent = JSON.parse(fs.readFileSync(datasourceJSONFile, 'utf8'));
} catch (err) {
debug(`Error reading file ${datasourceJSONFile}: ${err.message}`);
err.message = `Cannot load ${datasourceJSONFile}: ${err.message}`;
throw err;
}
const config = getDataSourceConfig(datasourcesDir, dataSourceClass);

for (const connector of Object.values(connectors)) {
const matchedConnector =
jsonFileContent.connector === connector.name ||
jsonFileContent.connector === `loopback-connector-${connector.name}`;
config.connector === connector.name ||
config.connector === `loopback-connector-${connector.name}`;

if (matchedConnector) return connectorType.includes(connector.baseModel);
}
Expand All @@ -614,37 +602,60 @@ exports.isConnectorOfType = function (
return null;
};

/**
*
* returns the name property inside the datasource json file
* @param {string} datasourcesDir path for sources
* @param {string} dataSourceClass class name for the datasoure
*/
exports.getDataSourceName = function (datasourcesDir, dataSourceClass) {
if (!dataSourceClass) {
return false;
}
let result;
let jsonFileContent;
function getDataSourceConfig(datasourcesDir, dataSourceClass) {
const config =
readDataSourceConfigFromTypeScript(datasourcesDir, dataSourceClass) ||
// Support legacy JSON-based configuration.
// TODO(semver-major) Print a deprecation warning for JSON-based datasources
// or stop supporting them entirely.
readDataSourceConfigFromJSON(datasourcesDir, dataSourceClass);

debug('datasource %s has config %o', dataSourceClass, config);
return config;
}

function readDataSourceConfigFromTypeScript(datasourcesDir, dataSourceClass) {
const srcFile = path.join(
datasourcesDir,
exports.dataSourceToArtifactFileName(dataSourceClass),
);
debug(
'Reading datasource config for class %s from %s',
dataSourceClass,
srcFile,
);

const fileContent = fs.readFileSync(srcFile, 'utf-8');
return tsquery.getDataSourceConfig(fileContent);
}

function readDataSourceConfigFromJSON(datasourcesDir, dataSourceClass) {
const datasourceJSONFile = path.join(
datasourcesDir,
exports.dataSourceToJSONFileName(dataSourceClass),
);

debug(`reading ${datasourceJSONFile}`);
debug(`Reading datasource config from JSON file ${datasourceJSONFile}`);
try {
jsonFileContent = JSON.parse(fs.readFileSync(datasourceJSONFile, 'utf8'));
return JSON.parse(fs.readFileSync(datasourceJSONFile, 'utf8'));
} catch (err) {
debug(`Error reading file ${datasourceJSONFile}: ${err.message}`);
err.message = `Cannot load ${datasourceJSONFile}: ${err.message}`;
throw err;
}
}

if (jsonFileContent.name) {
result = jsonFileContent.name;
/**
*
* returns the name property inside the datasource json file
* @param {string} datasourcesDir path for sources
* @param {string} dataSourceClass class name for the datasoure
*/
exports.getDataSourceName = function (datasourcesDir, dataSourceClass) {
if (!dataSourceClass) {
return false;
}
return result;
const config = getDataSourceConfig(datasourcesDir, dataSourceClass);
return config.name;
};

exports.dataSourceToJSONFileName = function (dataSourceClass) {
Expand All @@ -654,6 +665,12 @@ exports.dataSourceToJSONFileName = function (dataSourceClass) {
);
};

exports.dataSourceToArtifactFileName = function (dataSourceClass) {
return (
toFileName(dataSourceClass.replace('Datasource', '')) + '.datasource.ts'
);
};

exports.stringifyObject = function (data, options = {}) {
return stringifyObject(data, {
indent: ' ', // two spaces
Expand Down
Loading

0 comments on commit eb5774b

Please sign in to comment.