Skip to content

Commit ab91918

Browse files
authored
Merge pull request #424 from AntoineGautier/issue423_loader
Clean up loader
2 parents c20be88 + 0a8acce commit ab91918

File tree

10 files changed

+84
-71
lines changed

10 files changed

+84
-71
lines changed

server/scripts/parse-template-package.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {
99
getProject
1010
} from "../src/parser";
1111

12-
loadPackage("Buildings");
12+
loadPackage("Buildings.Templates");
1313

1414
const { options, scheduleOptions } = getOptions();
1515

server/src/parser/index.ts

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,12 @@ export { SystemTypeN as SystemType, Template } from "./template";
66

77
/**
88
*
9-
* @param packagePath Absolute path to package
9+
* @param packageName Full class name of package (e.g. "Library.Package.SubPackage")
1010
*
1111
* @returns Templates
1212
*/
13-
export function loadPackage(packagePath: string): templates.SystemTemplateN[] {
14-
//
15-
const parsedPath = path.parse(packagePath);
16-
parser.setPathPrefix(parsedPath.dir);
17-
parser.loadPackage(parsedPath.name);
18-
13+
export function loadPackage(packageName: string): templates.SystemTemplateN[] {
14+
parser.loadPackage(packageName);
1915
return templates.getTemplates().map((t) => t.getSystemTemplate());
2016
}
2117

@@ -37,4 +33,4 @@ export function getAllTemplates(): templates.Template[] {
3733

3834
export function getProject(): templates.Project {
3935
return templates.getProject();
40-
}
36+
}

server/src/parser/loader.ts

Lines changed: 48 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,36 @@ import { typeStore } from "./parser";
66
import config from "../../src/config";
77

88
export const TEMPLATE_IDENTIFIER = "__ctrlFlow_template";
9-
export const MODELICAPATH = [
9+
export let MODELICA_JSON_PATH = [
1010
`${config.MODELICA_DEPENDENCIES}/template-json/json/`,
1111
];
1212

13-
function _toModelicaPath(filePath: string) {
13+
// Used for testing: registers additional search paths for Modelica JSON files
14+
export function prependToModelicaJsonPath(paths: string[]) {
15+
MODELICA_JSON_PATH = [...paths, ...MODELICA_JSON_PATH];
16+
}
17+
18+
export function getClassNameFromRelativePath(filePath: string) {
1419
filePath = filePath.endsWith(".json") ? filePath.slice(0, -5) : filePath;
1520
return filePath.replace(/\//g, ".");
1621
}
1722

23+
/**
24+
* Finds all entry points that contain the template identifier for a given package.
25+
* - LIMITATION: This function requires that the package uses
26+
* [Directory Hierarchy Mapping](https://specification.modelica.org/maint/3.6/packages.html#directory-hierarchy-mapping)
27+
* @param packageName - The Modelica class name of the package to search for entry points
28+
* @returns An array of objects containing the path and parsed JSON for each entry point found
29+
*/
1830
export function findPackageEntryPoints(
19-
prefix: string,
20-
reference: string,
31+
packageName: string,
2132
): { path: string; json: Object | undefined }[] {
2233
const entryPoints: { path: string; json: Object | undefined }[] = [];
23-
[prefix, ...MODELICAPATH].forEach((dir) => {
24-
const dirPath = path.resolve(dir, reference);
34+
MODELICA_JSON_PATH.forEach((dir) => {
35+
// We need a top directory to look up for entry points
36+
// so we can simply convert the class name to a relative path
37+
// without adding any file extension.
38+
const dirPath = path.resolve(dir, packageName.replace(/\./g, "/"));
2539
if (fs.existsSync(dirPath)) {
2640
const cmd = `grep -rl ${dirPath} -e "${TEMPLATE_IDENTIFIER}"`;
2741
const response = execSync(cmd).toString();
@@ -32,10 +46,10 @@ export function findPackageEntryPoints(
3246
.sort((a, b) => (a.includes("package.json") ? -1 : 1))
3347
.map((p) => path.relative(dir, p))
3448
.map((p) => {
35-
const path = _toModelicaPath(p);
49+
const path = getClassNameFromRelativePath(p);
3650
return {
3751
path: path,
38-
json: loader(dir, path),
52+
json: loader(path),
3953
};
4054
}),
4155
);
@@ -46,33 +60,36 @@ export function findPackageEntryPoints(
4660
}
4761

4862
/**
49-
* Searched the provided directory for a given
50-
* @param prefix directory to search
51-
* @param filePath path to try and find
52-
*
53-
* @returns the found file path or null if not found
63+
* Gets the path to a Modelica JSON file based on the full class name.
64+
* - LIMITATION: This function requires that the library packages use
65+
* [Directory Hierarchy Mapping](https://specification.modelica.org/maint/3.6/packages.html#directory-hierarchy-mapping)
66+
* @param className - The full Modelica class name (e.g. "Library.Package.Class")
67+
* @param dirPath - The directory path to search in
68+
* @returns The file path if found, null otherwise
5469
*/
55-
function _findPath(prefix: string, reference: string): string | null {
56-
let filePath = path.parse(reference.replace(/\./g, "/"));
70+
function getPathFromClassName(
71+
className: string,
72+
dirPath: string,
73+
): string | null {
74+
let filePath = path.parse(className.replace(/\./g, "/"));
5775

58-
let jsonFile = path.resolve(prefix, filePath.dir, `${filePath.name}.json`);
76+
let jsonFile = path.resolve(dirPath, filePath.dir, `${filePath.name}.json`);
5977

6078
while (!fs.existsSync(jsonFile) && filePath.name) {
6179
// check if definition already exists
6280
// TODO - construct this path correctly...
6381
const curPath = path.relative(filePath.dir, filePath.name);
64-
const modelicaPath = _toModelicaPath(curPath);
82+
const modelicaPath = getClassNameFromRelativePath(curPath);
6583
if (typeStore.has(modelicaPath)) {
6684
break;
6785
}
6886
// package definitions break the typical modelica path to file mapping that
6987
// is used. A typical modelica path to file path look like:
70-
// 'Template.AirHandlerFans.VAVMultizone' -> 'Template/AirhandlerFans/VAVMultizone
88+
// 'Template.AirHandlerFans.VAVMultizone' -> 'Template/AirhandlerFans/VAVMultizone.json'
7189
// We need to support mapping like this as well:
72-
// 'Template.AirHandlerFans -> Template/AirhandlerFans/package'
73-
// 'package' files behave kind of like 'index.html' files
90+
// 'Template.AirHandlerFans -> Template/AirhandlerFans/package.json'
7491
jsonFile = path.resolve(
75-
prefix,
92+
dirPath,
7693
filePath.dir,
7794
filePath.name,
7895
"package.json",
@@ -81,20 +98,22 @@ function _findPath(prefix: string, reference: string): string | null {
8198
break;
8299
}
83100
filePath = path.parse(filePath.dir);
84-
jsonFile = path.resolve(prefix, filePath.dir, `${filePath.name}.json`);
101+
jsonFile = path.resolve(dirPath, filePath.dir, `${filePath.name}.json`);
85102
}
86103

87104
return fs.existsSync(jsonFile) ? jsonFile : null;
88105
}
89106

90-
// When given a path, loads types. returns null if not found
91-
export function loader(prefix: string, reference: string): Object | undefined {
92-
const modelicaDirs = [prefix, ...MODELICAPATH];
93-
107+
/**
108+
* Loads a Modelica JSON file given the full class name.
109+
* @param className The full Modelica class name to load (e.g. "Library.Package.Class")
110+
* @returns The loaded JSON object or undefined if not found
111+
*/
112+
export function loader(className: string): Object | undefined {
94113
// TODO: allow modelica paths
95-
if (!reference.startsWith("Modelica")) {
96-
for (const dir of modelicaDirs) {
97-
const jsonFile = _findPath(dir, reference);
114+
if (!className.startsWith("Modelica")) {
115+
for (const dir of MODELICA_JSON_PATH) {
116+
const jsonFile = getPathFromClassName(className, dir);
98117
if (jsonFile && fs.existsSync(jsonFile)) {
99118
return require(jsonFile);
100119
}

server/src/parser/parser.ts

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1141,28 +1141,26 @@ export class File {
11411141
}
11421142
}
11431143

1144-
let pathPrefix = "";
1145-
export function setPathPrefix(prefix: string) {
1146-
pathPrefix = prefix;
1147-
}
1148-
11491144
/**
11501145
* Extracts the given file into the type store
1146+
* @param filePath - The ***relative*** path to the file to load (e.g. "Buildings/Templates/File")
11511147
*/
1152-
export const getFile = (filePath: string) => {
1153-
const jsonData = loader(pathPrefix, filePath);
1148+
export const getFile = (className: string) => {
1149+
const jsonData = loader(className);
11541150
if (jsonData) {
1155-
return new File(jsonData, filePath);
1151+
return new File(jsonData, className);
11561152
} else {
11571153
// console.log(`Not found: ${filePath}`);
11581154
}
11591155
};
11601156

1161-
// Searches a package for templates, then loads the file
1162-
// creating template instances
1163-
export const loadPackage = (filePath: string) => {
1164-
const paths = findPackageEntryPoints(pathPrefix, filePath);
1165-
1157+
/**
1158+
* Searches a package for templates, then loads the file
1159+
* creating template instances.
1160+
* @param packageName - The full class name of the package to load (e.g. "Library.Package.SubPackage")
1161+
*/
1162+
export const loadPackage = (packageName: string) => {
1163+
const paths = findPackageEntryPoints(packageName);
11661164
paths?.map(({ json, path }) => new File(json, path));
11671165

11681166
// Attempt to load project settings from a pre-defined path

server/tests/integration/parser/expression.test.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
import { createTestModelicaJson, fullTempDirPath } from "./utils";
21
import { ModifiersN, getTemplates } from "../../../src/parser/template";
3-
import { loadPackage, getSystemTypes, Template } from "../../../src/parser/";
2+
import { loadPackage, Template } from "../../../src/parser/";
43
import { initializeTestModelicaJson } from "./utils";
54
import * as parser from "../../../src/parser/parser";
65
const testModelicaFile = "TestPackage.Template.TestTemplate";
@@ -10,8 +9,8 @@ let template: Template | undefined;
109

1110
describe("Expression", () => {
1211
beforeAll(() => {
13-
createTestModelicaJson();
14-
loadPackage(`${fullTempDirPath}/TestPackage`);
12+
initializeTestModelicaJson();
13+
loadPackage('TestPackage');
1514
const templates = getTemplates();
1615
template = templates.find(
1716
(t) => t.modelicaPath === templatePath,

server/tests/integration/parser/loader.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@ describe("Parser file loading", () => {
2121
});
2222

2323
it("Discovers template files and project options", () => {
24-
const packagePath = "TestPackage";
25-
const projectOptionsPath = "Buildings.Templates.Data.AllSystems";
26-
parser.loadPackage(packagePath);
27-
const projectOptionElement = parser.typeStore.find(projectOptionsPath);
24+
const packageName = "TestPackage";
25+
const projectOptionsClassName = "Buildings.Templates.Data.AllSystems";
26+
parser.loadPackage(packageName);
27+
const projectOptionElement = parser.typeStore.find(projectOptionsClassName);
2828
expect(projectOptionElement).toBeDefined();
2929
});
3030
});

server/tests/integration/parser/modifiers.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { createTestModelicaJson, fullTempDirPath } from "./utils";
1+
import { initializeTestModelicaJson } from "./utils";
22
import {
33
getTemplates,
44
Option,
@@ -21,8 +21,8 @@ const isExpression = (obj: any) =>
2121

2222
describe("Modifications", () => {
2323
beforeAll(() => {
24-
createTestModelicaJson();
25-
loadPackage(`${fullTempDirPath}/TestPackage`);
24+
initializeTestModelicaJson();
25+
loadPackage('TestPackage');
2626
const templates = getTemplates();
2727
const template = templates.find(
2828
(t) => t.modelicaPath === templatePath,

server/tests/integration/parser/path-expansion.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { createTestModelicaJson, fullTempDirPath } from "./utils";
1+
import { initializeTestModelicaJson } from "./utils";
22
import { loadPackage, getOptions } from "../../../src/parser/";
33
import { evaluateExpression } from "../../../src/parser/expression";
44

@@ -9,8 +9,8 @@ import { evaluateExpression } from "../../../src/parser/expression";
99

1010
describe("Path Expansion", () => {
1111
beforeAll(() => {
12-
createTestModelicaJson();
13-
loadPackage(`${fullTempDirPath}/TestPackage`);
12+
initializeTestModelicaJson();
13+
loadPackage('TestPackage');
1414
});
1515

1616
it("Parameter type paths are expanded", () => {

server/tests/integration/parser/template.test.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { createTestModelicaJson, fullTempDirPath } from "./utils";
1+
import { initializeTestModelicaJson } from "./utils";
22
import {
33
loadPackage,
44
getSystemTypes,
@@ -13,8 +13,8 @@ const NESTED_TEMPLATE_PATH =
1313

1414
describe("Template wrapper class functionality", () => {
1515
beforeAll(() => {
16-
createTestModelicaJson();
17-
loadPackage(`${fullTempDirPath}/TestPackage`);
16+
initializeTestModelicaJson();
17+
loadPackage('TestPackage');
1818
});
1919

2020
it("Extracts two templates and three Template types to be in stores", () => {
@@ -170,8 +170,8 @@ const PROJECT_INSTANCE_NAME = "datAll";
170170

171171
describe("'Project' items are extracted", () => {
172172
beforeAll(() => {
173-
createTestModelicaJson();
174-
loadPackage(`${fullTempDirPath}/TestPackage`);
173+
initializeTestModelicaJson();
174+
loadPackage('TestPackage');
175175
});
176176
it("Project is populated and all project options are included in options", () => {
177177
const project = getProject();

server/tests/integration/parser/utils.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import * as parser from "../../../src/parser/parser";
2+
import { prependToModelicaJsonPath } from '../../../src/parser/loader';
23
import { createModelicaJson } from "../../../scripts/generate-modelica-json";
34

45
// NOTE: if the test modelica package changes it will need to be
@@ -21,7 +22,7 @@ export function createTestModelicaJson() {
2122
*/
2223
export function initializeTestModelicaJson() {
2324
createTestModelicaJson();
24-
parser.setPathPrefix(fullTempDirPath);
25+
prependToModelicaJsonPath([fullTempDirPath]);
2526
}
2627

2728
type SimpleOption = {

0 commit comments

Comments
 (0)