@sprucelabs/spruce-cli
Version:
Command line interface for building Spruce skills.
340 lines (339 loc) • 18.8 kB
JavaScript
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const path_1 = __importDefault(require("path"));
const spruce_skill_utils_1 = require("@sprucelabs/spruce-skill-utils");
const spruce_skill_utils_2 = require("@sprucelabs/spruce-skill-utils");
const spruce_skill_utils_3 = require("@sprucelabs/spruce-skill-utils");
const test_utils_1 = require("@sprucelabs/test-utils");
const test_utils_2 = require("@sprucelabs/test-utils");
const SchemaStore_1 = require("../../../features/schema/stores/SchemaStore");
const AbstractSchemaTest_1 = __importDefault(require("../../../tests/AbstractSchemaTest"));
const test_utility_1 = __importDefault(require("../../../tests/utilities/test.utility"));
//TODO rethink how to check for count of files and results or where it may make sense to move this test
const TYPE_FILE_COUNT = 2; // (only fieldMap and field.types... schema.types checked by +1 in tests)
const SYNC_FILE_COUNT = Object.keys(SchemaStore_1.coreSchemas).length + TYPE_FILE_COUNT;
const MOCK_CORE_SYNC_FILE_COUNT = 4 + TYPE_FILE_COUNT;
class KeepsSchemasInSyncTest extends AbstractSchemaTest_1.default {
static coreSyncOptions = {
shouldGenerateCoreSchemaTypes: true,
};
static async hasSyncSchemaAction() {
await this.Cli();
test_utils_1.assert.isFunction(this.Action('schema', 'sync').execute);
}
static async failsBecauseSchemasIsNotInstalled() {
await this.Cli();
const err = await test_utils_1.assert.doesThrowAsync(() => this.Action('schema', 'sync').execute({}));
test_utils_2.errorAssert.assertError(err, 'FEATURE_NOT_INSTALLED');
}
static async syncingWithNoSchemasSucceeds() {
await this.installSchemaFeature('schemas');
const results = await this.Action('schema', 'sync').execute({});
test_utils_1.assert.isFalsy(results.errors);
//TODO determine better way to count files
test_utility_1.default.assertCountsByAction(results.files, {
updated: 0,
generated: SYNC_FILE_COUNT,
skipped: 0,
});
}
static async syncingWithNoSchemasAndFetchCoreSchemasFalseSucceeds() {
await this.installSchemaFeature('schemas');
const results = await this.Action('schema', 'sync').execute({
shouldFetchCoreSchemas: false,
});
test_utils_1.assert.isFalsy(results.errors);
test_utility_1.default.assertCountsByAction(results.files, {
updated: 0,
generated: TYPE_FILE_COUNT,
skipped: 0,
});
}
static async syncingCleansUpTempFiles() {
await this.installSchemaFeature('schemas');
const results = await this.Action('schema', 'sync').execute({});
test_utils_1.assert.isFalsy(results.errors);
const tmpFile = this.resolveHashSprucePath('schemas', 'tmp', 'valueType.tmp.ts');
test_utils_1.assert.isFalse(spruce_skill_utils_2.diskUtil.doesFileExist(tmpFile));
}
static async syncingCoreSchemasGeneratesTypesFile() {
await this.installSchemaFeature('schemas');
await this.copyMockCoreSchemas();
const results = await this.Action('schema', 'sync').execute(this.coreSyncOptions);
test_utils_1.assert.isUndefined(results.errors);
test_utils_1.assert.isTruthy(results.files);
test_utils_1.assert.isLength(results.files, MOCK_CORE_SYNC_FILE_COUNT);
test_utility_1.default.assertCountsByAction(results.files, {
generated: MOCK_CORE_SYNC_FILE_COUNT,
skipped: 0,
updated: 0,
});
test_utils_1.assert.isTrue(spruce_skill_utils_2.diskUtil.doesFileExist(this.coreSchemaTypesFile));
await this.assertTypesFileGeneratesArraySelect(this.coreSchemaTypesFile);
}
static async syncSchemasTwiceSkipsFiles() {
await this.syncSchemas('schemas', this.coreSyncOptions);
const results = await this.Action('schema', 'sync').execute(this.coreSyncOptions);
test_utils_1.assert.isFalsy(results.errors);
test_utils_1.assert.isAbove(results.files?.length, 0);
test_utility_1.default.assertCountsByAction(results.files, {
generated: 0,
skipped: results.files?.length ?? 0,
updated: 0,
});
}
static async makeSureSchemaTypesAreVersioned() {
await this.installSchemaFeature('schemas');
await this.copyMockCoreSchemas();
const results = await this.Action('schema', 'sync').execute(this.coreSyncOptions);
test_utils_1.assert.isFalsy(results.errors);
const typesContents = spruce_skill_utils_2.diskUtil.readFile(this.coreSchemaTypesFile);
test_utils_1.assert.doesInclude(typesContents, new RegExp(`SpruceSchemas.${spruce_skill_utils_3.CORE_NAMESPACE}.${spruce_skill_utils_3.CORE_SCHEMA_VERSION.constValue}(.*?)interface Person`, 'gis'));
}
static async shouldGenerateCoreSchemaTypesGeneratesValidFiles() {
await this.installSchemaFeature('schemas');
await this.copyMockCoreSchemas();
const results = await this.Action('schema', 'sync').execute(this.coreSyncOptions);
test_utils_1.assert.isFalsy(results.errors);
test_utils_1.assert.isTruthy(results.files);
await this.assertValidActionResponseFiles(results);
const typesContents = spruce_skill_utils_2.diskUtil.readFile(this.coreSchemaTypesFile);
test_utils_1.assert.doesNotInclude(typesContents, /\/spruce-core-schemas/gi);
test_utils_1.assert.doesInclude(typesContents, new RegExp(`export declare namespace ${spruce_skill_utils_3.DEFAULT_GLOBAL_SCHEMA_NAMESPACE}.${spruce_skill_utils_3.CORE_NAMESPACE}.${spruce_skill_utils_3.CORE_SCHEMA_VERSION.constValue}`, 'gis'));
const orgSchema = test_utility_1.default.assertFileByNameInGeneratedFiles('organization.schema.ts', results.files);
const locationSchemaContents = spruce_skill_utils_2.diskUtil.readFile(orgSchema);
test_utils_1.assert.doesInclude(locationSchemaContents, 'SchemaRegistry');
}
static async generateCoreSchemaInCoreSchemasModule() {
await this.installSchemaFeature('schemas');
const pkg = this.Service('pkg');
pkg.set({ path: 'name', value: '@sprucelabs/spruce-core-schemas' });
await this.copyMockCoreSchemas();
const results = await this.Action('schema', 'sync').execute({});
test_utils_1.assert.isFalsy(results.errors);
test_utils_1.assert.isTruthy(results.files);
const typesContents = spruce_skill_utils_2.diskUtil.readFile(this.coreSchemaTypesFile);
test_utils_1.assert.doesNotInclude(typesContents, /\/spruce-core-schemas/gi);
test_utils_1.assert.doesInclude(typesContents, new RegExp(`export declare namespace ${spruce_skill_utils_3.DEFAULT_GLOBAL_SCHEMA_NAMESPACE}.${spruce_skill_utils_3.CORE_NAMESPACE}.${spruce_skill_utils_3.CORE_SCHEMA_VERSION.constValue}`, 'gis'));
const orgSchema = test_utility_1.default.assertFileByNameInGeneratedFiles('organization.schema.ts', results.files);
const locationSchemaContents = spruce_skill_utils_2.diskUtil.readFile(orgSchema);
test_utils_1.assert.doesInclude(locationSchemaContents, 'SchemaRegistry');
}
static async canHandleHyphenSchemaIds() {
await this.syncSchemas('schemas');
const createResponse = await this.Action('schema', 'create').execute({
nameReadable: 'Test schema',
nameCamel: 'testSchema',
});
test_utils_1.assert.isFalsy(createResponse.errors);
const builderPath = test_utility_1.default.assertFileByNameInGeneratedFiles('testSchema.builder.ts', createResponse.files);
const contents = spruce_skill_utils_2.diskUtil
.readFile(builderPath)
.replace("id: 'testSchema'", "id: 'test-schema'");
spruce_skill_utils_2.diskUtil.writeFile(builderPath, contents);
const syncResults = await this.Action('schema', 'sync').execute({});
const testSchema = test_utility_1.default.assertFileByNameInGeneratedFiles('test-schema.schema.ts', syncResults.files);
const testSchemaContents = spruce_skill_utils_2.diskUtil.readFile(testSchema);
test_utils_1.assert.doesInclude(testSchemaContents, 'SchemaRegistry');
await this.assertValidActionResponseFiles(syncResults);
}
static async coreSchemasPullFromCoreSchemasModuleDuringNormalGeneration() {
await this.syncSchemas('schemas');
const createResponse = await this.Action('schema', 'create').execute({
nameReadable: 'Test schema',
nameCamel: 'testSchema',
});
for (const schema of Object.values(SchemaStore_1.coreSchemas)) {
const id = schema.id;
const match = test_utility_1.default.assertFileByNameInGeneratedFiles(`${id}.schema.ts`, createResponse.files);
const contents = spruce_skill_utils_2.diskUtil.readFile(match);
test_utils_1.assert.doesInclude(contents, `export { ${id}Schema as default } from '@sprucelabs/spruce-core-schemas'`);
}
}
static async schemasStayInSyncWhenBuildersAreDeleted() {
await this.syncSchemas('schemas');
const version = spruce_skill_utils_1.versionUtil.generateVersion();
const typeChecker = this.Service('typeChecker');
const createAction = this.Action('schema', 'create');
const matcher = new RegExp(`SpruceSchemas.TestingSchemas.${version.constValue}(.*?)interface TestSchema`, 'gis');
test_utils_1.assert.isTrue(spruce_skill_utils_2.diskUtil.doesFileExist(path_1.default.dirname(this.schemaTypesFile)));
const createResponse = await createAction.execute({
nameReadable: 'Test schema',
nameCamel: 'testSchema',
});
const builderFile = test_utility_1.default.assertFileByNameInGeneratedFiles(/testSchema\.builder/, createResponse.files);
// make sure builder is versioned
test_utils_1.assert.doesInclude(builderFile, version.dirValue);
const schemaFile = test_utility_1.default.assertFileByNameInGeneratedFiles(/testSchema\.schema/, createResponse.files);
// make sure this path is versioned
test_utils_1.assert.doesInclude(schemaFile, version.dirValue);
test_utils_1.assert.doesInclude(schemaFile, '/testingSchemas/');
// schema types should be good
await typeChecker.check(this.schemaTypesFile);
// the types should include our test schema
let typesContents = spruce_skill_utils_2.diskUtil.readFile(this.schemaTypesFile);
test_utils_1.assert.doesInclude(typesContents, matcher);
// the schema file should exist
test_utils_1.assert.isTrue(spruce_skill_utils_2.diskUtil.doesFileExist(schemaFile));
// DELETE builder and make sure we are cleaned up
spruce_skill_utils_2.diskUtil.deleteFile(builderFile);
// this should cleanup types and schema files
await this.Action('schema', 'sync').execute({});
test_utils_1.assert.isTrue(spruce_skill_utils_2.diskUtil.doesFileExist(this.schemaTypesFile));
// and the schema should have been deleted
test_utils_1.assert.isFalse(spruce_skill_utils_2.diskUtil.doesFileExist(schemaFile));
// and the namespace folder should have been deleted
const namespaceFolder = this.resolveHashSprucePath('schemas', 'testingSChemas');
test_utils_1.assert.isFalse(spruce_skill_utils_2.diskUtil.doesDirExist(namespaceFolder));
}
static async canSyncSchemasWhenOnlyNodeModuleIsInstalledAfterDecliningToInstallSkill() {
await this.FeatureFixture().installCachedFeatures('schemasInNodeModule');
const promise = this.Action('schema', 'sync').execute({});
await this.waitForInput();
await this.ui.sendInput('n');
await this.waitForInput();
await this.ui.sendInput('');
const results = await promise;
test_utils_1.assert.isFalsy(results.errors);
await this.assertValidActionResponseFiles(results);
}
static async syncsExpectedFields() {
await this.syncSchemas('schemas');
const schemasDir = this.resolvePath('src', 'schemas');
await spruce_skill_utils_2.diskUtil.copyDir(this.resolveTestPath('test_builders'), schemasDir);
const results = await this.Action('schema', 'sync').execute({});
const schema = await this.importSchema(results, 'schemaTwo.schema.ts');
test_utils_1.assert.isUndefined(schema.fields.phone.minArrayLength);
test_utils_1.assert.isEqual(schema.fields.favoriteColors.minArrayLength, 3);
test_utils_1.assert.isEqual(schema.fields.permissions.minArrayLength, 0);
}
static async canChangeSkillNamespace() {
await this.syncSchemas('schemas');
await this.Action('schema', 'create').execute({
nameReadable: 'Test schema',
nameCamel: 'testSchema',
});
const beforeFolder = this.resolveHashSprucePath('schemas', 'testingSchemas');
const afterFolder = this.resolveHashSprucePath('schemas', 'newNamespace');
test_utils_1.assert.isTrue(spruce_skill_utils_2.diskUtil.doesFileExist(beforeFolder));
test_utils_1.assert.isFalse(spruce_skill_utils_2.diskUtil.doesFileExist(afterFolder));
await this.Store('skill').setCurrentSkillsNamespace('new-namespace');
await this.Action('schema', 'sync').execute({});
test_utils_1.assert.isFalse(spruce_skill_utils_2.diskUtil.doesFileExist(beforeFolder));
test_utils_1.assert.isTrue(spruce_skill_utils_2.diskUtil.doesFileExist(afterFolder));
}
static async generatedSchemasRetainImportsAndTypeSuffix() {
await this.installSchemaFeature('schemas');
const results = await this.Action('schema', 'create').execute({
nameReadable: 'Test schema',
nameCamel: 'testSchema',
});
const testSchemaPath = test_utility_1.default.assertFileByNameInGeneratedFiles('testSchema.builder.ts', results.files);
spruce_skill_utils_2.diskUtil.writeFile(testSchemaPath, `import { buildSchema } from '@sprucelabs/schema'
export default buildSchema({
id: 'testSchema',
name: 'Test schema',
description: '',
importsWhenLocal: ['import * as Local from "@sprucelabs/schema"'],
importsWhenRemote: ['import * as Remote from "@sprucelabs/schema"'],
typeSuffix: '<S extends Record<string, any> = Record<string, any>>',
fields: {
fieldName1: {
type: 'text',
label: 'First Field',
isRequired: true,
},
fieldName2: {
type: 'number',
label: 'Second Field',
isRequired: true,
hint: 'A hint',
},
},
})
`);
const syncResults = await this.Action('schema', 'sync').execute({});
const schemaPath = test_utility_1.default.assertFileByNameInGeneratedFiles('testSchema.schema.ts', syncResults.files);
const imported = await this.Service('import').importDefault(schemaPath);
test_utils_1.assert.doesInclude(imported, {
importsWhenRemote: ['import * as Remote from "@sprucelabs/schema"'],
typeSuffix: '<S extends Record<string, any> = Record<string, any>>',
});
}
static async importSchema(results, filename) {
const file = test_utility_1.default.assertFileByNameInGeneratedFiles(filename, results.files);
const schema = await this.Service('import').importDefault(file);
return schema;
}
static async assertTypesFileGeneratesArraySelect(typesFile) {
const contents = spruce_skill_utils_2.diskUtil.readFile(typesFile);
test_utils_1.assert.doesInclude(contents, `'favoriteColors'?: ("blue" | "red")[]`);
}
static async copyMockCoreSchemas() {
const source = this.resolveTestPath('mock_core_builders');
const destination = this.resolvePath('src', 'schemas');
await spruce_skill_utils_2.diskUtil.copyDir(source, destination);
}
}
exports.default = KeepsSchemasInSyncTest;
__decorate([
(0, test_utils_1.test)()
], KeepsSchemasInSyncTest, "hasSyncSchemaAction", null);
__decorate([
(0, test_utils_1.test)()
], KeepsSchemasInSyncTest, "failsBecauseSchemasIsNotInstalled", null);
__decorate([
(0, test_utils_1.test)()
], KeepsSchemasInSyncTest, "syncingWithNoSchemasSucceeds", null);
__decorate([
(0, test_utils_1.test)()
], KeepsSchemasInSyncTest, "syncingWithNoSchemasAndFetchCoreSchemasFalseSucceeds", null);
__decorate([
(0, test_utils_1.test)()
], KeepsSchemasInSyncTest, "syncingCleansUpTempFiles", null);
__decorate([
(0, test_utils_1.test)()
], KeepsSchemasInSyncTest, "syncingCoreSchemasGeneratesTypesFile", null);
__decorate([
(0, test_utils_1.test)()
], KeepsSchemasInSyncTest, "syncSchemasTwiceSkipsFiles", null);
__decorate([
(0, test_utils_1.test)()
], KeepsSchemasInSyncTest, "makeSureSchemaTypesAreVersioned", null);
__decorate([
(0, test_utils_1.test)()
], KeepsSchemasInSyncTest, "shouldGenerateCoreSchemaTypesGeneratesValidFiles", null);
__decorate([
(0, test_utils_1.test)()
], KeepsSchemasInSyncTest, "generateCoreSchemaInCoreSchemasModule", null);
__decorate([
(0, test_utils_1.test)()
], KeepsSchemasInSyncTest, "canHandleHyphenSchemaIds", null);
__decorate([
(0, test_utils_1.test)()
], KeepsSchemasInSyncTest, "coreSchemasPullFromCoreSchemasModuleDuringNormalGeneration", null);
__decorate([
(0, test_utils_1.test)()
], KeepsSchemasInSyncTest, "schemasStayInSyncWhenBuildersAreDeleted", null);
__decorate([
(0, test_utils_1.test)()
], KeepsSchemasInSyncTest, "canSyncSchemasWhenOnlyNodeModuleIsInstalledAfterDecliningToInstallSkill", null);
__decorate([
(0, test_utils_1.test)('syncs minArrayLength, importsWhenRemote')
], KeepsSchemasInSyncTest, "syncsExpectedFields", null);
__decorate([
(0, test_utils_1.test)()
], KeepsSchemasInSyncTest, "canChangeSkillNamespace", null);
__decorate([
(0, test_utils_1.test)()
], KeepsSchemasInSyncTest, "generatedSchemasRetainImportsAndTypeSuffix", null);
//# sourceMappingURL=KeepingSchemasInSync.test.js.map