From c4ecf3119dc69b591750190376cec95cf5fe212b Mon Sep 17 00:00:00 2001 From: Gery Hirschfeld Date: Tue, 19 Mar 2024 13:43:06 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20fix(devkit):=20adjust=20tsconfig?= =?UTF-8?q?=20for=20build=20(#1361)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * adjust tsconfig for build * revert to old setup for schematics * format files * fix lint issue * fix styles migration for windows * update docs * fix lint issue * update changesets --- .changeset/great-peaches-tan.md | 5 + .changeset/heavy-penguins-watch.md | 5 + .changeset/quick-months-rhyme.md | 5 + .changeset/unlucky-cameras-jam.md | 2 +- .gitignore | 5 + .prettierignore | 2 + .../00-guides/00-getting-started.stories.mdx | 4 +- .../02-upgrade/upgrade-guide.v16.stories.mdx | 2 +- package-lock.json | 161 ++---------------- packages/devkit/.eslintignore | 2 + packages/devkit/.eslintrc.json | 10 +- packages/devkit/.npmignore | 4 + packages/devkit/package.json | 18 +- packages/devkit/project.json | 17 +- packages/devkit/src/ng-upgrade-16/index.ts | 1 - packages/devkit/tsconfig.json | 31 +++- packages/devkit/tsconfig.lib.json | 26 --- packages/styles/bin/index.mjs | 39 +++-- 18 files changed, 115 insertions(+), 224 deletions(-) create mode 100644 .changeset/great-peaches-tan.md create mode 100644 .changeset/heavy-penguins-watch.md create mode 100644 .changeset/quick-months-rhyme.md create mode 100644 packages/devkit/.npmignore delete mode 100644 packages/devkit/tsconfig.lib.json diff --git a/.changeset/great-peaches-tan.md b/.changeset/great-peaches-tan.md new file mode 100644 index 0000000000..7c5008467c --- /dev/null +++ b/.changeset/great-peaches-tan.md @@ -0,0 +1,5 @@ +--- +'@baloise/ds-core': patch +--- + +**css**: support new grid class names like `grid` and `col` diff --git a/.changeset/heavy-penguins-watch.md b/.changeset/heavy-penguins-watch.md new file mode 100644 index 0000000000..bd36c9c5c7 --- /dev/null +++ b/.changeset/heavy-penguins-watch.md @@ -0,0 +1,5 @@ +--- +'@baloise/ds-core': patch +--- + +**styles**: fix paths in the migration script for windows diff --git a/.changeset/quick-months-rhyme.md b/.changeset/quick-months-rhyme.md new file mode 100644 index 0000000000..fd24be924e --- /dev/null +++ b/.changeset/quick-months-rhyme.md @@ -0,0 +1,5 @@ +--- +'@baloise/ds-core': patch +--- + +**devkit**: fix build issue of ng-add schematics diff --git a/.changeset/unlucky-cameras-jam.md b/.changeset/unlucky-cameras-jam.md index d7a23152ac..d3ddc8f079 100644 --- a/.changeset/unlucky-cameras-jam.md +++ b/.changeset/unlucky-cameras-jam.md @@ -2,4 +2,4 @@ '@baloise/ds-core': patch --- -**styles**: add migration for compact theme and grid +**styles**: add migration for compact theme diff --git a/.gitignore b/.gitignore index d9084d5e31..88b2ff5531 100644 --- a/.gitignore +++ b/.gitignore @@ -61,6 +61,11 @@ packages/favicons/CHANGELOG.md packages/fonts/CHANGELOG.md packages/icons/CHANGELOG.md +packages/devkit/src/**/*.js +packages/devkit/src/**/*.js.map +packages/devkit/src/**/*.d.ts + + libs/output-targets-angular/CHANGELOG.md libs/output-targets-react/CHANGELOG.md libs/output-targets-vue/CHANGELOG.md diff --git a/.prettierignore b/.prettierignore index c44da6757a..bb1b849a9b 100644 --- a/.prettierignore +++ b/.prettierignore @@ -9,6 +9,8 @@ packages/maps/src/markers.json packages/core/icons packages/core/src/utils/constants/icons.constant.ts packages/core/src/components.d.ts +packages/devkit/src/**/*.js +packages/devkit/src/**/*.d.ts resources/data/tags.json diff --git a/docs/stories/development/00-guides/00-getting-started.stories.mdx b/docs/stories/development/00-guides/00-getting-started.stories.mdx index 1c94f1fab9..92a720ff6c 100644 --- a/docs/stories/development/00-guides/00-getting-started.stories.mdx +++ b/docs/stories/development/00-guides/00-getting-started.stories.mdx @@ -50,7 +50,7 @@ If the projects requires translations, then install [\{TRANSLOCO\}](https://ngne Configure project: ```bash -ng add @ngneat/transloco +npx ng add @ngneat/transloco # On an nx workspace nx g @ngneat/transloco:ng-add ``` @@ -64,7 +64,7 @@ Lets install the schematics to configure and add the design system to an Angular Install the library using Angular CLI: ```bash -ng add @baloise/ds-devkit +npx ng add @baloise/ds-devkit # On an nx workspace nx g @baloise/ds-devkit:ng-add ``` diff --git a/docs/stories/development/02-upgrade/upgrade-guide.v16.stories.mdx b/docs/stories/development/02-upgrade/upgrade-guide.v16.stories.mdx index b1b714b3c6..b486ac4870 100644 --- a/docs/stories/development/02-upgrade/upgrade-guide.v16.stories.mdx +++ b/docs/stories/development/02-upgrade/upgrade-guide.v16.stories.mdx @@ -111,7 +111,7 @@ npm add -D -E @baloise/ds-devkit 2. **Angular Schematics Script:** Rename the packages by simply run the following command in your project's root directory: ```bash -ng generate @baloise/ds-devkit:up16 +npx ng generate @baloise/ds-devkit:up16 ``` 3. **Verify the Changes:** Once the script has run, review the changes to ensure everything has been updated correctly. It's a good practice to check the git diff if your project is version-controlled. diff --git a/package-lock.json b/package-lock.json index f85c9245af..cdb4799cef 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22694,105 +22694,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/copyfiles": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/copyfiles/-/copyfiles-2.4.1.tgz", - "integrity": "sha512-fereAvAvxDrQDOXybk3Qu3dPbOoKoysFMWtkY3mv5BsL8//OSZVL5DCLYqgRfY5cWirgRzlC+WSrxp6Bo3eNZg==", - "dev": true, - "dependencies": { - "glob": "^7.0.5", - "minimatch": "^3.0.3", - "mkdirp": "^1.0.4", - "noms": "0.0.0", - "through2": "^2.0.1", - "untildify": "^4.0.0", - "yargs": "^16.1.0" - }, - "bin": { - "copyfiles": "copyfiles", - "copyup": "copyfiles" - } - }, - "node_modules/copyfiles/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/copyfiles/node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/copyfiles/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/copyfiles/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/copyfiles/node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/copyfiles/node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true, - "engines": { - "node": ">=10" - } - }, "node_modules/core-js-compat": { "version": "3.36.0", "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.36.0.tgz", @@ -36770,40 +36671,6 @@ "node": ">=14" } }, - "node_modules/noms": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/noms/-/noms-0.0.0.tgz", - "integrity": "sha512-lNDU9VJaOPxUmXcLb+HQFeUgQQPtMI24Gt6hgfuMHRJgMRHMF/qZ4HJD3GDru4sSw9IQl2jPjAYnQrdIeLbwow==", - "dev": true, - "dependencies": { - "inherits": "^2.0.1", - "readable-stream": "~1.0.31" - } - }, - "node_modules/noms/node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", - "dev": true - }, - "node_modules/noms/node_modules/readable-stream": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "node_modules/noms/node_modules/string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", - "dev": true - }, "node_modules/nopt": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.0.tgz", @@ -48879,17 +48746,11 @@ "version": "16.0.1", "license": "Apache-2.0", "dependencies": { - "@angular-devkit/core": "~15.0.5", - "@angular-devkit/schematics": "~15.0.5", - "@schematics/angular": "~15.0.5", - "glob": "~10.3.10" - }, - "devDependencies": { - "copyfiles": "~2.4.1" - }, - "peerDependencies": { - "@angular/common": ">=15.0.0", - "@angular/core": ">=15.0.0" + "@angular-devkit/core": "^17.0.10", + "@angular-devkit/schematics": "^17.0.10", + "@schematics/angular": "^17.0.10", + "glob": "~10.3.10", + "typescript": "~5.2.2" } }, "packages/devkit/node_modules/@angular-devkit/core": { @@ -48985,6 +48846,18 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "packages/devkit/node_modules/typescript": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "packages/favicons": { "name": "@baloise/ds-favicons", "version": "16.0.1", diff --git a/packages/devkit/.eslintignore b/packages/devkit/.eslintignore index a6a96a04dc..9e5cfce327 100644 --- a/packages/devkit/.eslintignore +++ b/packages/devkit/.eslintignore @@ -1,3 +1,5 @@ node_modules dist files +src/**/*.js +src/**/*.d.ts diff --git a/packages/devkit/.eslintrc.json b/packages/devkit/.eslintrc.json index 6e5f95dcc0..3bb9b168b4 100644 --- a/packages/devkit/.eslintrc.json +++ b/packages/devkit/.eslintrc.json @@ -21,7 +21,15 @@ "@nx/dependency-checks": [ "error", { - "ignoredDependencies": ["@angular/common", "@angular/core", "tslib"] + "ignoredDependencies": [ + "@angular/common", + "@angular/core", + "@angular-devkit/core", + "@angular-devkit/schematics", + "@schematics/angular", + "typescript", + "tslib" + ] } ] } diff --git a/packages/devkit/.npmignore b/packages/devkit/.npmignore new file mode 100644 index 0000000000..7c31f4692f --- /dev/null +++ b/packages/devkit/.npmignore @@ -0,0 +1,4 @@ + +# Ignores TypeScript files, but keeps definitions. +*.ts +!*.d.ts diff --git a/packages/devkit/package.json b/packages/devkit/package.json index 1efbe6cec7..d929de9c07 100644 --- a/packages/devkit/package.json +++ b/packages/devkit/package.json @@ -11,21 +11,15 @@ }, "homepage": "https://design.baloise.dev", "license": "Apache-2.0", - "dependencies": { - "@angular-devkit/core": "~15.0.5", - "@angular-devkit/schematics": "~15.0.5", - "@schematics/angular": "~15.0.5", - "glob": "~10.3.10" - }, - "peerDependencies": { - "@angular/common": ">=15.0.0", - "@angular/core": ">=15.0.0" - }, "schematics": "./src/collection.json", "ng-add": { "save": "devDependencies" }, - "devDependencies": { - "copyfiles": "~2.4.1" + "dependencies": { + "@angular-devkit/core": "^17.0.10", + "@angular-devkit/schematics": "^17.0.10", + "@schematics/angular": "^17.0.10", + "typescript": "~5.2.2", + "glob": "~10.3.10" } } diff --git a/packages/devkit/project.json b/packages/devkit/project.json index 2b7731483a..0be8783ade 100644 --- a/packages/devkit/project.json +++ b/packages/devkit/project.json @@ -7,31 +7,20 @@ "nx-release-publish": { "executor": "@nx/js:release-publish", "options": { - "packageRoot": "{projectRoot}/dist" - } - }, - "prepare": { - "executor": "@nx/js:tsc", - "outputs": ["{options.outputPath}"], - "options": { - "outputPath": "{projectRoot}/dist", - "main": "{projectRoot}/src/index.ts", - "tsConfig": "{projectRoot}/tsconfig.lib.json", - "assets": ["{projectRoot}/**/files/**", "{projectRoot}/src/**/*.json"] + "packageRoot": "{projectRoot}" } }, "build": { "executor": "nx:run-commands", - "dependsOn": ["^build", "prepare"], "options": { "cwd": "{projectRoot}", - "command": "copyfiles src/*/schema.json src/*/files/** src/collection.json dist" + "command": "tsc -p tsconfig.json" } }, "link": { "executor": "nx:run-commands", "options": { - "cwd": "{projectRoot}/dist", + "cwd": "{projectRoot}", "command": "npm link" } } diff --git a/packages/devkit/src/ng-upgrade-16/index.ts b/packages/devkit/src/ng-upgrade-16/index.ts index 696e88ae40..bde3db6efb 100644 --- a/packages/devkit/src/ng-upgrade-16/index.ts +++ b/packages/devkit/src/ng-upgrade-16/index.ts @@ -180,7 +180,6 @@ function updateSassImports(): Rule { recorder.remove(0, content.length) recorder.insertLeft(0, newContent) tree.commitUpdate(recorder) - _context.logger.info(`Updated import in ${path}`) } } }) diff --git a/packages/devkit/tsconfig.json b/packages/devkit/tsconfig.json index a3370d0314..49a6f1cd38 100644 --- a/packages/devkit/tsconfig.json +++ b/packages/devkit/tsconfig.json @@ -1,11 +1,24 @@ { - "extends": "../../tsconfig.base.json", - "compilerOptions": {}, - "files": [], - "include": [], - "references": [ - { - "path": "./tsconfig.lib.json" - } - ] + "compilerOptions": { + "baseUrl": "tsconfig", + "lib": ["es2018", "dom"], + "declaration": true, + "module": "commonjs", + "moduleResolution": "node", + "noEmitOnError": true, + "noFallthroughCasesInSwitch": true, + "noImplicitAny": true, + "noImplicitThis": true, + "noUnusedParameters": true, + "noUnusedLocals": true, + "rootDir": "src/", + "skipDefaultLibCheck": true, + "skipLibCheck": true, + "sourceMap": true, + "strictNullChecks": true, + "target": "es6", + "types": ["node"] + }, + "include": ["src/**/*"], + "exclude": ["src/*/files/**/*"] } diff --git a/packages/devkit/tsconfig.lib.json b/packages/devkit/tsconfig.lib.json deleted file mode 100644 index b25e8bc850..0000000000 --- a/packages/devkit/tsconfig.lib.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "dist/out-tsc", - "baseUrl": ".", - "lib": ["es2018", "dom"], - "declaration": true, - "module": "commonjs", - "moduleResolution": "node", - "noEmitOnError": true, - "noFallthroughCasesInSwitch": true, - "noImplicitAny": true, - "noImplicitThis": true, - "noUnusedParameters": true, - "noUnusedLocals": true, - "rootDir": "src", - "skipDefaultLibCheck": true, - "skipLibCheck": true, - "sourceMap": true, - "strictNullChecks": true, - "target": "es6", - "types": ["node"] - }, - "include": ["src/**/*"], - "exclude": ["src/**/*.spec.ts", "src/**/*.test.ts", "src/*/files/**/*"] -} diff --git a/packages/styles/bin/index.mjs b/packages/styles/bin/index.mjs index 7088f80699..473973b68f 100755 --- a/packages/styles/bin/index.mjs +++ b/packages/styles/bin/index.mjs @@ -177,19 +177,22 @@ async function migrateComponentStylesSheet({ log, isDirectory, directoryPath, fi const files = [] if (isDirectory) { const relativePath = path.relative(process.cwd(), directoryPath) - files.push(path.join(relativePath, '**', '*.scss').replace(/\\/g, '/')) - files.push(path.join(relativePath, '**', '*.sass').replace(/\\/g, '/')) + files.push(path.join(relativePath, '**', '*.scss')) + files.push(path.join(relativePath, '**', '*.sass')) } else { const relativePath = path.relative(process.cwd(), filePath) - files.push(relativePath.replace(/\\/g, '/')) + files.push(relativePath) } try { const result = await replace({ - files, + files: files.map(f => path.normalize(f)), from: [new RegExp(`@baloise/(ds-css|design-system-css)/sass/mixins`, 'g')], to: ['@baloise/ds-styles/sass/mixins'], allowEmptyPaths: true, + glob: { + windowsPathsNoEscape: true, + }, }) printResult({ result, log }) } catch (error) { @@ -205,16 +208,16 @@ async function migrateCSSVariables({ log, isDirectory, directoryPath, filePath } const files = [] if (isDirectory) { const relativePath = path.relative(process.cwd(), directoryPath) - files.push(path.join(relativePath, '**', '*.sass').replace(/\\/g, '/')) - files.push(path.join(relativePath, '**', '*.scss').replace(/\\/g, '/')) + files.push(path.join(relativePath, '**', '*.sass')) + files.push(path.join(relativePath, '**', '*.scss')) } else { const relativePath = path.relative(process.cwd(), filePath) - files.push(relativePath.replace(/\\/g, '/')) + files.push(relativePath) } try { const result = await replace({ - files, + files: files.map(f => path.normalize(f)), from: [ ...replacementsCSSVariablesColors.from, ...replacementsCSSVariablesVarious.from, @@ -232,6 +235,9 @@ async function migrateCSSVariables({ log, isDirectory, directoryPath, filePath } ...replacementsCSSVariablesInvertedPrimary.to, ], allowEmptyPaths: true, + glob: { + windowsPathsNoEscape: true, + }, }) printResult({ result, log }) } catch (error) { @@ -244,7 +250,7 @@ async function migrateCSSVariables({ log, isDirectory, directoryPath, filePath } } async function migrateGlobalStyleSheet({ globalStyleSheetPath, log }) { - const files = globalStyleSheetPath.replace(/\\/g, '/') + const files = path.normalize(globalStyleSheetPath) try { const result = await replace({ files, @@ -298,9 +304,13 @@ async function migrateGlobalStyleSheet({ globalStyleSheetPath, log }) { '@baloise/ds-styles/css/themes/compact', ], allowEmptyPaths: true, + glob: { + windowsPathsNoEscape: true, + }, }) printResult({ result, log }) - let lines = (await fsp.readFile(files, 'utf-8')).split(/\r?\n/) + const content = await fsp.readFile(files, 'utf-8') + let lines = content.split(/\r?\n/) lines.push(`@import '@baloise/ds-styles/css/utilities/interaction';`) lines.push(`@import '@baloise/ds-styles/css/utilities/sizing';`) lines = lines.reduce((acc, line) => { @@ -373,15 +383,15 @@ async function migrateInlineTemplates({ filePath, log, utilReplacers }) { async function migrateHtmlFiles({ filePath, log, utilReplacers }) { // check if path is directly one file const isFile = filePath.trim().endsWith('.html') - let files = filePath.replace(/\\/g, '/') + let files = filePath if (!isFile) { - files = path.join(`${files}`, '**', '*.html'.replace(/\\/g, '/')) + files = path.join(`${files}`, '**', '*.html') } try { const results = [ await replace({ - files, + files: path.normalize(files), processor: input => { const $ = load(input) let content = input @@ -405,6 +415,9 @@ async function migrateHtmlFiles({ filePath, log, utilReplacers }) { return content }, allowEmptyPaths: true, + glob: { + windowsPathsNoEscape: true, + }, }), ]