Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: compile error when new .cds files are added to memfs #2969

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/serious-suits-beam.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sap-ux/fiori-annotation-api': patch
---

Fixed CDS compile error when new .cds files are created in memfs.
17 changes: 17 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,23 @@
},
"cwd": "${workspaceFolder}/packages/cds-annotation-parser"
},
{
"type": "node",
"request": "launch",
"name": "cds-odata-annotation-converter: Debug Current Jest File",
"program": "${workspaceFolder}/node_modules/jest/bin/jest.js",
"args": ["${fileBasenameNoExtension}", "--config", "jest.config.js", "--coverage=false", "--runInBand"],
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen",
"disableOptimisticBPs": true,
"windows": {
"program": "${workspaceFolder}/node_modules/jest/bin/jest"
},
"cwd": "${workspaceFolder}/packages/cds-odata-annotation-converter",
"env": {
"UX_DEBUG": "false"
}
},
{
"type": "node",
"request": "launch",
Expand Down
2 changes: 1 addition & 1 deletion packages/cds-odata-annotation-converter/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"@sap-ux/cds-annotation-parser": "workspace:*",
"@sap-ux/odata-annotation-core": "workspace:*",
"@sap-ux/odata-vocabularies": "workspace:*",
"@sap/ux-cds-compiler-facade": "1.16.0",
"@sap/ux-cds-compiler-facade": "1.16.1",
"i18next": "20.6.1",
"@sap-ux/text-document-utils": "workspace:*"
},
Expand Down
1 change: 1 addition & 0 deletions packages/fiori-annotation-api/jest.setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const fiveMinutes = 5 * 60000;
const TEST_DATA_ROOT = join(__dirname, 'test', 'data');
const CDS_PROJECTS = [
join(TEST_DATA_ROOT, 'cds', 'cap-start'),
join(TEST_DATA_ROOT, 'cds', 'cap-no-apps'),
join(TEST_DATA_ROOT, 'cds', 'layering'),
join(TEST_DATA_ROOT, 'cds', 'term-deletion')
];
Expand Down
2 changes: 1 addition & 1 deletion packages/fiori-annotation-api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"@sap-ux/project-access": "workspace:*",
"@sap-ux/vocabularies-types": "0.13.0",
"@sap-ux/xml-odata-annotation-converter": "workspace:*",
"@sap/ux-cds-compiler-facade": "1.16.0",
"@sap/ux-cds-compiler-facade": "1.16.1",
"@xml-tools/ast": "5.0.5",
"@xml-tools/parser": "1.0.11",
"mem-fs": "2.1.0",
Expand Down
10 changes: 8 additions & 2 deletions packages/fiori-annotation-api/src/cds/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,17 @@ import type { CDSService, TextFile } from '../types';
*
* @param projectRoot - Absolute path of the project.
* @param serviceName - Name of the CDS service.
* @param fileCache
* @param clearCache - Flag indicating if the CDS file resolution cache should be cleared.
* @returns CDS service structure.
*/
export async function getCDSService(projectRoot: string, serviceName: string, clearCache = false): Promise<CDSService> {
const files = await getCdsFiles(projectRoot, clearCache);
export async function getCDSService(
projectRoot: string,
serviceName: string,
fileCache: Map<string, string>,
clearCache = false
): Promise<CDSService> {
const files = await getCdsFiles(projectRoot, fileCache, clearCache);
const serviceFiles = files.map((uri): TextFile => {
return { uri: pathToFileURL(uri).toString(), isReadOnly: uri.indexOf('node_modules') !== -1 };
});
Expand Down
18 changes: 10 additions & 8 deletions packages/fiori-annotation-api/src/fiori-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ export class FioriAnnotationService {
project.projectType === 'CAPJava' || project.projectType === 'CAPNodejs'
);
const finalOptions = getOptionsWithDefaults(options);
const service = await getService(project, serviceName, appName, finalOptions.clearFileResolutionCache);
const service = await getService(project, serviceName, appName, fs, finalOptions.clearFileResolutionCache);
const adapter = createAdapter(
project,
service,
Expand Down Expand Up @@ -241,12 +241,6 @@ export class FioriAnnotationService {
this.fileCache.set(file.uri, file.content);
}

// all the modified files should also be included in the cache
for (const [relativePath, value] of Object.entries(this.fs.dump())) {
const absolute = pathToFileURL(join(process.cwd(), relativePath)).toString();
this.fileCache.set(absolute, value.contents);
}

await this.adapter.sync(this.fileCache);
this.isInitialSyncCompleted = true;
}
Expand Down Expand Up @@ -470,12 +464,20 @@ async function getService(
project: Project,
serviceName: string,
appName: string,
fsEditor: Editor | undefined,
clearCache: boolean
): Promise<Service> {
if (project.projectType === 'EDMXBackend') {
return getLocalEDMXService(project, serviceName, appName);
} else if (project.projectType === 'CAPJava' || project.projectType === 'CAPNodejs') {
return getCDSService(project.root, serviceName, clearCache);
const fileCache = new Map<string, string>();
if (fsEditor) {
for (const [relativePath, value] of Object.entries(fsEditor.dump())) {
const absolute = pathToFileURL(join(process.cwd(), relativePath)).toString();
fileCache.set(absolute, value.contents);
}
}
return getCDSService(project.root, serviceName, fileCache, clearCache);
} else {
throw new Error(`Unsupported project type "${project.projectType}"!`);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
namespace scp.cloud;

using {
managed,
cuid,
sap.common
} from '@sap/cds/common';

type Url : String;

type TechnicalBooleanFlag : Boolean @(
UI.Hidden,
Core.Computed
);
type Criticality : Integer @(
UI.Hidden,
Core.Computed
);

type Identifier : String(100)@(title : 'Identifier');
@cds.autoexpose
abstract entity identified : cuid {
identifier : Identifier not null;
}

//Bolded display of first table column values can be achieved by defining annotations Common.SemanticKey and
//Common.TextArrangement for the entities key and referring to a 'human-readable' identifier to be displayed instead.

annotate identified with @(
Common.SemanticKey : [identifier],
UI.Identification : [{Value : identifier}]
) {

ID @Common : {
Text : identifier,
TextArrangement : #TextOnly

};
}
entity Incidents : managed, identified {
title : String(50) @title : '{i18n>Title}';
category : Association to one Category @title : '{i18n>Category}';
priority : Association to one Priority @title : '{i18n>Priority}';
incidentStatus : Association to one IncidentStatus @title : '{i18n>IncidentStatus}';
description : String(1000) @title : '{i18n>IncidentDescription}';
assignedIndividual : Association to one Individual;
incidentFlow : Association to many IncidentFlow
on incidentFlow.incident = $self;
incidentProcessTimeline : Association to many IncidentProcessTimeline
on incidentProcessTimeline.incident = $self;
processingThreshold : Association to one ProcessingThreshold
on processingThreshold.incident = $self;
}

entity ProcessingThreshold {
key id : String(10);
processingDays : Integer;
processingLimit : Integer;
incident : Association to one Incidents;
}
entity IncidentFlow : managed {
key id : UUID;
processStep : String(30)@title : '{i18n>ProcessStep}';
stepStatus : String(10)@title : '{i18n>ProcessStepStatus}';
criticality : Integer;
stepStartDate : Date @title : '{i18n>StepStartDate}';
stepEndDate : Date @title : '{i18n>StepEndDate}';
incident : Association to Incidents;
}

entity IncidentProcessTimeline : managed {
key id : UUID;
text : String;
type : String;
startTime : DateTime;
endTime : DateTime;
incident : Association to Incidents;
}

entity Individual : managed {
key id : UUID;
//Begin add additional properties
businessPartnerID : String;
addressID : String;
//End add additional properties
Incidents : Association to many Incidents
on Incidents.assignedIndividual = $self;
}

entity IncidentsCodeList : common.CodeList {
key code : String(20);
}

entity Category : IncidentsCodeList {}

entity Priority : IncidentsCodeList {
criticality : Criticality not null default 3;
}

entity IncidentStatus : IncidentsCodeList {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"name": "teched2020-iis360",
"version": "1.0.0",
"description": "A simple CAP project.",
"repository": "<Add your repository here>",
"license": "UNLICENSED",
"private": true,
"dependencies": {
"@sap/cds": "6.7.0"
},
"devDependencies": {},
"cds": {
"requires": {
"db": {
"kind": "sql"
}
},
"odata": {
"version": "v4"
}
},
"scripts": {
"start": "cds run"
},
"sapux": []
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
namespace scp.cloud;
using IncidentService as service from './incidentservice';

using {
cuid
} from '@sap/cds/common';

annotate cuid with {
ID @(
title : '{i18n>ID}',
UI.HiddenFilter,
Core.Computed
);
}


annotate service.Incidents with {
ID @UI.Hidden: true;
assignedIndividual @UI.Hidden : true;
};

annotate service.Incidents with {
incidentStatus @Common : {
Text : incidentStatus.code,
TextArrangement : #TextOnly,
ValueListWithFixedValues
};
category @Common : {
Text : category.code,
TextArrangement : #TextOnly,
ValueListWithFixedValues
};
priority @Common : {
Text : priority.code,
TextArrangement : #TextOnly,
ValueListWithFixedValues
};
};

annotate service.Category with {
code @Common : {
Text : name,
TextArrangement : #TextOnly
} @title : '{i18n>Category}'
};

annotate service.Priority with {
code @Common : {
Text : name,
TextArrangement : #TextOnly
} @title : '{i18n>Priority}'
};

annotate service.IncidentStatus with {
code @Common : {
Text : name,
TextArrangement : #TextOnly
} @title : '{i18n>IncidentStatus}'
};

annotate service.Incidents with @(
Aggregation.ApplySupported : {
$Type : 'Aggregation.ApplySupportedType',
Transformations : [
'aggregate',
'topcount',
'bottomcount',
'identity',
'concat',
'groupby',
'filter',
'expand',
'top',
'skip',
'orderby',
'search'
],
GroupableProperties : [
category_code
],
AggregatableProperties : [
{
$Type : 'Aggregation.AggregatablePropertyType',
Property : ID
}
]
},
Analytics.AggregatedProperties : [{
Name : 'IncidentsPerCategory',
AggregationMethod : 'countdistinct',
AggregatableProperty : ID,
![@Common.Label] : '{i18n>IncidentsPerCategory}'
}]
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using scp.cloud from '../db/schema';

service IncidentService {

entity Incidents as projection on cloud.Incidents;

entity IncidentFlow as projection on cloud.IncidentFlow;

entity IncidentProcessTimeline as projection on cloud.IncidentProcessTimeline;

entity ProcessingThreshold as projection on cloud.ProcessingThreshold;

entity Individual as projection on cloud.Individual;

entity Category as projection on cloud.Category;

entity Priority as projection on cloud.Priority;

}
20 changes: 19 additions & 1 deletion packages/fiori-annotation-api/test/unit/fiori-service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -664,7 +664,25 @@ describe('fiori annotation service', () => {
expect(serialize(metadata.schema, PROJECTS.V4_CDS_START.root)).toMatchSnapshot();
});

test('new file from memfs', async () => {
test('new file from memfs, no apps', async () => {
const project = PROJECTS.V4_CAP_NO_APPS;
const root = project.root;
const fsEditor = await createFsEditorForProject(root);
const servicesFilePath = pathFromUri(project.files.services);
const newFileName = 'new-file';
const appName = 'incidents';
const testData = `using from './${appName}/${newFileName}';\n`;
const annotationFilePath = join(root, 'app', appName, `${newFileName}.cds`);
fsEditor.write(annotationFilePath, '');
fsEditor.write(servicesFilePath, testData);

const service = await testRead(project.root, [], 'IncidentService', fsEditor);
const annotations = service.getSchema().schema.annotations;

expect(annotations[pathToFileURL(servicesFilePath).toString()]).toHaveLength(0);
expect(annotations[pathToFileURL(annotationFilePath).toString()]).toHaveLength(0);
});
test('new file from memfs, existing service file', async () => {
const project = PROJECTS.V4_CDS_START;
const root = project.root;
const fsEditor = await createFsEditorForProject(root);
Expand Down
Loading