Skip to content

Commit 3caffa2

Browse files
authored
Ensure all UMB_ constants is exported (#17683)
* export consts * remove lexer * init work on test for all consts to be exported * temporary solution to working test * fix test * fix one consts * update package-lock * remove imports * fix auto generation of test * correct test * important mistake correction * fix workspace * fix webhooks * fix users * UMB_CREATE_USER_CLIENT_CREDENTIAL_MODAL_ALIAS * fix user group * fix tree const exports * tiptap const exports * fix templates consts export * tags * stylesheets * static files * settings * static file system * section * search * scripts * fix tsc * relation * relation-type * recycle bin * property type * picker * partial views * tsc corrections * fix circular * package * member * member type * move constants to constants file * member group + documnet type * media * media-type * revert tsconfig change * log viewer * language * imaging * healt check * entity actions * user permissions * adjust test text * document * update consts * document type etc * blueprint * dictionary * data-type * current-user * culture * content-type * circular dependency * block-list * block-grid * fix type import * auto lint fixes * fix tsc * update test * make sure always to call check-const-generation * fix circular dependencies * consts for content package
1 parent 07c236c commit 3caffa2

File tree

926 files changed

+2829
-1022
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

926 files changed

+2829
-1022
lines changed
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
import fs from 'fs';
2+
import path from 'path';
3+
import { createImportMap } from '../importmap/index.js';
4+
5+
6+
const excludeTheseMaps = [
7+
'@umbraco-cms/backoffice/models',
8+
'@umbraco-cms/backoffice/markdown-editor',
9+
'@umbraco-cms/backoffice/external/',
10+
]
11+
12+
13+
/**
14+
* Recursively fetch all TypeScript files in the given directory.
15+
* @param {string} dir Directory path to scan.
16+
* @returns {string[]} List of file paths.
17+
*/
18+
function getTsFiles(dir) {
19+
let files = [];
20+
for (const file of fs.readdirSync(dir)) {
21+
const fullPath = path.join(dir, file);
22+
if (fs.statSync(fullPath).isDirectory()) {
23+
files = files.concat(getTsFiles(fullPath));
24+
} else if (file.endsWith('.ts')) {
25+
files.push(fullPath);
26+
}
27+
}
28+
return files;
29+
}
30+
31+
/**
32+
* Extract constants starting with "UMB_" from a file.
33+
* @param {string} filePath Path to the file to analyze.
34+
* @returns {string[]} List of exported UMB_ constants.
35+
*/
36+
function findUmbConstants(filePath) {
37+
const content = fs.readFileSync(filePath, 'utf-8');
38+
const lines = content.split('\n');
39+
const umbConstants = [];
40+
41+
for (const line of lines) {
42+
// Match export const UMB_* syntax
43+
const match = line.match(/export\s+const\s+([A-Za-z_][A-Za-z0-9_]*)/);
44+
if (match && match[1].startsWith('UMB_')) {
45+
umbConstants.push(match[1]);
46+
}
47+
}
48+
49+
return umbConstants;
50+
}
51+
52+
/**
53+
* Main function to find UMB_ constants from package.json exports.
54+
* @param {string} projectRoot Root directory of the project (defaults to `process.cwd()`).
55+
* @returns {Promise<boolean>} Resolves to true if all constants are valid; false otherwise.
56+
*/
57+
export async function findUmbConstExports() {
58+
59+
const __dirname = import.meta.dirname;
60+
const projectRoot = path.join(__dirname, '../../');
61+
const packageJsonPath = path.join(projectRoot, 'tsconfig.json');
62+
63+
// Step 1: Validate package.json existence and read exports field
64+
if (!fs.existsSync(packageJsonPath)) {
65+
throw new Error('Error: package.json not found in the project root.');
66+
}
67+
68+
const packageSource = fs.readFileSync(packageJsonPath, 'utf-8');
69+
const packageSourceWithoutComment = packageSource.slice(packageSource.indexOf('*/') + 2);
70+
const packageJson = JSON.parse(packageSourceWithoutComment);
71+
const exportsField = packageJson.compilerOptions.paths;
72+
73+
if (!exportsField) {
74+
throw new Error('Error: No "exports" field found in package.json.');
75+
}
76+
77+
78+
const foundConsts = Object.entries(exportsField).map(([key, value]) => {
79+
const path = value[0];
80+
if(path && excludeTheseMaps.some(x => path.indexOf(x) === 0) === false) {
81+
const found = checkPackageExport(projectRoot, path);
82+
83+
return `{
84+
path: '${key}',
85+
consts: ${JSON.stringify(found)}
86+
}`;
87+
}
88+
return true;
89+
}).filter(x => typeof(x) === 'string' && x != '');
90+
91+
92+
const content = `export const foundConsts = [${foundConsts.join(',\n')}];`;
93+
94+
const outputPath = path.join(projectRoot, './utils/all-umb-consts/index.ts');
95+
fs.writeFileSync(outputPath, content);
96+
97+
generatetestImportFile(projectRoot);
98+
99+
}
100+
101+
function checkPackageExport(projectRoot, packagePath) {
102+
// Step 2: Scan JavaScript files for exported "UMB_" constants
103+
//console.log('Scanning for exported "UMB_" constants...');gener
104+
// remove file from path:
105+
const packageFolder = packagePath.replace(/\/[^/]+$/, '');
106+
const jsFiles = getTsFiles(packageFolder);
107+
108+
const umbConstants = [];
109+
110+
for (const filePath of jsFiles) {
111+
const constants = findUmbConstants(filePath);
112+
if (constants.length > 0) {
113+
umbConstants.push(...constants);
114+
}
115+
}
116+
117+
return umbConstants;
118+
119+
120+
}
121+
122+
123+
124+
function generatetestImportFile(projectRoot) {
125+
126+
const importmap = createImportMap({
127+
rootDir: './src',
128+
replaceModuleExtensions: true,
129+
});
130+
131+
const paths = Object.keys(importmap.imports).filter((path) => excludeTheseMaps.some(x => path.indexOf(x) === 0) === false);
132+
133+
const importEnties = [];
134+
const dictionaryEntries = [];
135+
136+
paths.forEach((path, i) => {
137+
importEnties.push(`import * as import${i.toString()} from '${path}';`);
138+
dictionaryEntries.push(`{
139+
path: '${path}',
140+
package: import${i.toString()}
141+
}`);
142+
});
143+
144+
const content = `
145+
${importEnties.join('\n')}
146+
147+
export const imports = [
148+
${dictionaryEntries.join(',\n')}
149+
];
150+
`
151+
152+
const outputPath = path.join(projectRoot, './utils/all-umb-consts/imports.ts');
153+
fs.writeFileSync(outputPath, content);
154+
}
155+
156+
157+
158+
159+
// run it self:
160+
(async () => {
161+
try {
162+
await findUmbConstExports();
163+
} catch (error) {
164+
console.error(error.message);
165+
process.exit(1);
166+
}
167+
})();

src/Umbraco.Web.UI.Client/devops/importmap/index.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ export const createImportMap = (args) => {
1515
let modulePath = value;
1616
if (typeof args.rootDir !== 'undefined') modulePath = modulePath.replace(/^\.\/dist-cms/, args.rootDir);
1717
if (args.replaceModuleExtensions) modulePath = modulePath.replace('.js', '.ts');
18-
console.log('replacing', value, 'with', modulePath);
1918
const importAlias = `${packageJsonName}/${moduleName}`;
2019

2120
imports[importAlias] = modulePath;

src/Umbraco.Web.UI.Client/package-lock.json

Lines changed: 1 addition & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Umbraco.Web.UI.Client/package.json

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@
172172
"generate:jsonschema:imports": "node ./devops/json-schema-generator/index.js",
173173
"generate:jsonschema:dist": "typescript-json-schema --required --include \"./src/json-schema/umbraco-package-schema.ts\" --out dist-cms/umbraco-package-schema.json tsconfig.json UmbracoPackage",
174174
"generate:jsonschema": "typescript-json-schema --required --include \"./src/json-schema/umbraco-package-schema.ts\"",
175+
"generate:check-const-test": "node ./devops/generate-check-const-test/index.js",
175176
"lint:errors": "npm run lint -- --quiet",
176177
"lint:fix": "npm run lint -- --fix",
177178
"lint": "eslint src",
@@ -181,10 +182,10 @@
181182
"storybook:preview": "npm run wc-analyze && storybook build && npx serve storybook-static",
182183
"storybook": "npm run wc-analyze && storybook dev -p 6006",
183184
"test:e2e": "npm run backoffice:test:e2e",
184-
"test:dev": "web-test-runner --config ./web-test-runner.dev.config.mjs",
185-
"test:dev-watch": "web-test-runner --watch --config ./web-test-runner.dev.config.mjs",
186-
"test:watch": "web-test-runner --watch",
187-
"test": "web-test-runner",
185+
"test:dev": "npm run generate:check-const-test && web-test-runner --config ./web-test-runner.dev.config.mjs",
186+
"test:dev-watch": "npm run generate:check-const-test && web-test-runner --watch --config ./web-test-runner.dev.config.mjs",
187+
"test:watch": "npm run generate:check-const-test && web-test-runner --watch",
188+
"test": "npm run generate:check-const-test && web-test-runner",
188189
"wc-analyze:vscode": "wca **/*.element.ts --format vscode --outFile dist-cms/vscode-html-custom-data.json",
189190
"wc-analyze": "wca **/*.element.ts --outFile dist-cms/custom-elements.json",
190191
"generate:tsconfig": "node ./devops/tsconfig/index.js",

src/Umbraco.Web.UI.Client/src/apps/app/app-oauth.element.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import './app-error.element.js';
88
*/
99
@customElement('umb-app-oauth')
1010
export class UmbAppOauthElement extends UmbLitElement {
11-
1211
/**
1312
* Set to true if the login failed. A message will be shown instead of the loader.
1413
* @attr

src/Umbraco.Web.UI.Client/src/apps/app/app.element.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { UmbAppContext } from './app.context.js';
44
import { UmbServerConnection } from './server-connection.js';
55
import { UmbAppAuthController } from './app-auth.controller.js';
66
import { UmbApiInterceptorController } from './api-interceptor.controller.js';
7+
import type { UmbAppOauthElement } from './app-oauth.element.js';
78
import type { UMB_AUTH_CONTEXT } from '@umbraco-cms/backoffice/auth';
89
import { UmbAuthContext } from '@umbraco-cms/backoffice/auth';
910
import { css, html, customElement, property } from '@umbraco-cms/backoffice/external/lit';
@@ -20,7 +21,6 @@ import {
2021
} from '@umbraco-cms/backoffice/extension-registry';
2122
import { filter, first, firstValueFrom } from '@umbraco-cms/backoffice/external/rxjs';
2223
import { hasOwnOpener, retrieveStoredPath } from '@umbraco-cms/backoffice/utils';
23-
import type { UmbAppOauthElement } from './app-oauth.element.js';
2424

2525
import './app-oauth.element.js';
2626

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
import { expect } from '@open-wc/testing';
2+
import { foundConsts } from '../utils/all-umb-consts/index.js';
3+
import { imports } from '../utils/all-umb-consts/imports.js';
4+
5+
describe('Export consts', () => {
6+
it('all consts are exported', async () => {
7+
const filteredConsts = foundConsts.filter(
8+
(foundConst) =>
9+
foundConst.path.indexOf('@umbraco-cms/backoffice/external') === -1 && foundConst.consts?.length > 0,
10+
);
11+
12+
/*console.log(
13+
'filteredConsts',
14+
filteredConsts.map((x, i) => 'import * as import' + i + " from '" + x.path + "';"),
15+
);*/
16+
17+
// Check if all consts are exported
18+
//const valid = await validateConstants(filteredConsts[6].consts, imports[6], filteredConsts[6].path);
19+
20+
/*
21+
const invalid = (
22+
await Promise.all(
23+
imports.map((p: any, i: number) => {
24+
if (i === filteredConsts.length) {
25+
console.log('No consts found for', i);
26+
throw new Error('No consts found for ' + i);
27+
}
28+
return validateConstants(filteredConsts[i].consts, p, filteredConsts[i].path);
29+
}),
30+
)
31+
).some((x) => x === false);
32+
*/
33+
34+
const invalid = (
35+
await Promise.all(
36+
filteredConsts.map(async (entry) => {
37+
/*
38+
try {
39+
if (await validatePackage(foundConst.consts, foundConst.path)) {
40+
console.log(`All consts is exported from ${foundConst.path}`);
41+
return true;
42+
} else {
43+
console.log(`Missing consts is exported from ${foundConst.path}`);
44+
return false;
45+
}
46+
} catch (e) {
47+
console.error(`Could not validate consts in ${foundConst.path}`);
48+
return;
49+
}
50+
*/
51+
const p = imports.find((x) => x.path === entry.path);
52+
if (p?.package) {
53+
return await validateConstants(entry.consts, p.package, entry.path);
54+
} else {
55+
throw new Error(`Could not validate consts in ${entry.path}, was unable to load package`);
56+
}
57+
}),
58+
)
59+
).some((x) => x !== true);
60+
61+
expect(invalid).to.be.false;
62+
});
63+
});
64+
65+
async function validatePackage(constants: Array<string>, packagePath: string) {
66+
const contentOfPackage = await import(packagePath);
67+
68+
return validateConstants(constants, contentOfPackage, packagePath);
69+
}
70+
71+
async function validateConstants(constants: Array<string>, contentOfPackage: any, packagePath: string) {
72+
let allValid = true;
73+
74+
for (const constant of constants) {
75+
let isExported = false;
76+
77+
for (const key in contentOfPackage) {
78+
if (key === constant) {
79+
isExported = true;
80+
break;
81+
}
82+
/*
83+
const value = contentOfPackage[key];
84+
console.log('value...', value);
85+
if (typeof value === 'string' && value.includes(constant)) {
86+
isExported = true;
87+
break;
88+
}
89+
if (typeof value === 'object') {
90+
console.log('object...', value);
91+
for (const subKey in value) {
92+
console.log('subKey', subKey);
93+
if (subKey === constant) {
94+
isExported = true;
95+
break;
96+
}
97+
}
98+
}
99+
*/
100+
}
101+
102+
if (!isExported) {
103+
console.error(`Error: Constant "${constant}" is not exported of ${packagePath}`);
104+
allValid = false;
105+
}
106+
}
107+
108+
return allValid;
109+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from './block-grid-area-config-entry.context-token.js';
2+
export * from './workspace/constants.js';
Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1 @@
1-
export * from './block-grid-area-config-entry.context-token.js';
21
export * from './block-grid-area-config-entry.element.js';
3-
export * from './workspace/index.js';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import type UmbBlockGridAreaTypeWorkspaceContext from './block-grid-area-type-workspace.context.js';
2+
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
3+
import type { UmbWorkspaceContext } from '@umbraco-cms/backoffice/workspace';
4+
5+
export const UMB_BLOCK_GRID_AREA_TYPE_WORKSPACE_CONTEXT = new UmbContextToken<
6+
UmbWorkspaceContext,
7+
UmbBlockGridAreaTypeWorkspaceContext
8+
>(
9+
'UmbWorkspaceContext',
10+
undefined,
11+
(context): context is UmbBlockGridAreaTypeWorkspaceContext =>
12+
(context as any).IS_BLOCK_GRID_AREA_TYPE_WORKSPACE_CONTEXT,
13+
);

0 commit comments

Comments
 (0)