You're Invited:Meet the Socket Team at BlackHat and DEF CON in Las Vegas, Aug 4-6.RSVP
Socket
Book a DemoInstallSign in
Socket

angular-server-side-configuration

Package Overview
Dependencies
Maintainers
1
Versions
67
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

angular-server-side-configuration - npm Package Compare versions

Comparing version

to
9.0.0-next.0

src/main.d.ts

12

builders/ngsscbuild/index.d.ts

@@ -1,2 +0,10 @@

declare const _default: import("@angular-devkit/architect/src/internal").Builder<import("../../models").Options>;
export default _default;
import { JsonObject } from '@angular-devkit/core';
interface Schema {
additionalEnvironmentVariables: string[];
aotSupport: boolean;
browserTarget: string;
ngsscEnvironmentFile: string;
filePattern: string | null;
}
declare const _default: import("@angular-devkit/architect/src/internal").Builder<Schema & JsonObject>;
export { _default as default, Schema as NgsscBuildSchema };

@@ -1,5 +0,227 @@

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const architect_1 = require("@angular-devkit/architect");
const ngssc_builder_1 = require("./ngssc-builder");
exports.default = architect_1.createBuilder(ngssc_builder_1.NgsscBuilder.build);
'use strict';
var architect = require('@angular-devkit/architect');
var crypto = require('crypto');
var fs = require('fs');
var path = require('path');
var util = require('util');
var typescript = require('typescript');
/**
* Detect environment variables in given file.
* @public
*/
class VariableDetector {
detect(fileContent) {
const fileMetaData = typescript.createSourceFile('environment.ts', fileContent, typescript.ScriptTarget.ESNext, true);
const { variant, variantImport } = this._detectVariant(fileMetaData);
const variables = variant === 'process'
? this._findProcessEnvVariables(fileMetaData)
: this._findNgEnvVariables(fileMetaData);
return {
variables: variables.sort((a, b) => b.variable.length - a.variable.length),
variant,
variantImport,
};
}
_detectVariant(node) {
const variantImport = this._findNodesOfType(node, typescript.SyntaxKind.ImportDeclaration)
.map(n => n.getFullText().trim())
.filter(n => n.includes('angular-server-side-configuration'))[0];
if (!variantImport || variantImport.match(/angular-server-side-configuration\/process/)) {
return { variant: 'process', variantImport };
}
const variant = variantImport.match(/angular-server-side-configuration\/ng-env/) ? 'NG_ENV' : undefined;
if (!variant) {
throw new Error('Could not detect variant (expected either process or ng-env)');
}
return { variant, variantImport };
}
_findProcessEnvVariables(node) {
return this._findUsages(node, 'process')
.sort((a, b) => b.parent.parent.getText().length - a.parent.parent.getText().length)
.map(n => ({
expression: this._resolveExpression(n.parent),
variable: n.parent.parent.getText().split('.')[2],
}));
}
_findNgEnvVariables(node) {
return this._findUsages(node, 'NG_ENV')
.filter(n => n.kind === typescript.SyntaxKind.Identifier && n.parent.kind !== typescript.SyntaxKind.ImportSpecifier)
.sort((a, b) => b.parent.getText().length - a.parent.getText().length)
.map(n => ({
expression: this._resolveExpression(n),
variable: n.parent.getText().split('.')[1],
}));
}
_findNodesOfType(node, kind) {
return node
.getChildren()
.map(c => this._findNodesOfType(c, kind))
.reduce((current, next) => current.concat(...next), node.kind === kind ? [node] : []);
}
_findUsages(node, variant) {
return node
.getChildren()
.map(c => this._findUsages(c, variant))
.reduce((current, next) => current.concat(next), node.getText() === variant ? [node] : []);
}
_resolveExpression(node) {
while (true) {
if (!typescript.SyntaxKind[node.parent.kind].endsWith('Expression')) {
return node.getText();
}
node = node.parent;
}
}
}
/**
* The result class for VariableTokenizer.
* @public
*/
class TokenizeResult {
constructor(content, _variables) {
this.content = content;
this._variables = _variables;
}
untokenize(fileContent) {
if (!this._variables.some(v => fileContent.includes(v.token))) {
return fileContent;
}
return this._variables.reduce((current, next) => current
.replace(new RegExp(`"${next.token}"`, 'g'), next.expression)
.replace(new RegExp(`"${next.token}`, 'g'), `(${next.expression}) + "`)
.replace(new RegExp(`${next.token}"`, 'g'), `" + (${next.expression})`)
.replace(new RegExp(`${next.token}`, 'g'), `" + (${next.expression}) + "`), fileContent);
}
}
/**
* Tokenize variables in a given file.
* @public
*/
class VariableTokenizer {
constructor() {
this._tokenCounter = 0;
}
tokenize(sourceContent, ngsscContext) {
const tokenizedVariables = ngsscContext.variables
.map(v => ({ ...v, token: `ngssc-token-${++this._tokenCounter}-${Date.now()}` }));
const tokenizedFileContent = tokenizedVariables
.reduce((current, next) => current.replace(next.expression, `"${next.token}" as any`), this._adaptImport(sourceContent, ngsscContext));
return new TokenizeResult(tokenizedFileContent, tokenizedVariables);
}
_adaptImport(fileContent, ngsscContext) {
return ngsscContext.variant === 'process' || !ngsscContext.variantImport
? fileContent
: fileContent.replace(ngsscContext.variantImport, `import 'angular-server-side-configuration/ng-env';`);
}
}
const readFileAsync = util.promisify(fs.readFile);
const writeFileAsync = util.promisify(fs.writeFile);
const unlinkAsync = util.promisify(fs.unlink);
const readdirAsync = util.promisify(fs.readdir);
class NgsscBuilder {
constructor(_options, _context) {
this._options = _options;
this._context = _context;
this._detector = new VariableDetector();
this._tokenizer = new VariableTokenizer();
this._browserTarget = architect.targetFromTargetString(_options.browserTarget);
this._ngsscEnvironmentFile = path.join(_context.workspaceRoot, _options.ngsscEnvironmentFile);
this._tmpNgsscEnvironmentFile = `${_options.ngsscEnvironmentFile}_${crypto.randomBytes(10).toString('hex')}.tmp`;
this._context.addTeardown(() => this._removeTmpNgsscEnvironmentFile());
}
async run() {
try {
return await this._safeRun();
}
catch (e) {
this._context.logger.error(e.toString());
return process.exit(2);
}
}
async _safeRun() {
const ngsscContext = await this._detectVariables();
const rawOptions = await this._prepareBrowserOptions(ngsscContext);
const browserTarget = this._browserTarget;
const browserName = await this._context.getBuilderNameForTarget(browserTarget);
const browserOptions = await this._context.validateOptions(rawOptions, browserName);
const scheduledTarget = await this._context.scheduleTarget(browserTarget, browserOptions);
const result = await scheduledTarget.result;
await this._buildNgsscJson(ngsscContext, browserOptions);
await this._untokenize(browserOptions);
await this._removeTmpNgsscEnvironmentFile();
return result;
}
async _detectVariables() {
const fileContent = await readFileAsync(this._ngsscEnvironmentFile, 'utf8');
const ngsscContext = await this._detector.detect(fileContent);
this._context.logger.info(`ngssc: Detected variant '${ngsscContext.variant}' with variables ` +
`'${ngsscContext.variables.map(v => v.variable).join(', ')}'`);
return ngsscContext;
}
async _prepareBrowserOptions(ngsscContext) {
const rawBrowserOptions = await this._context.getTargetOptions(this._browserTarget);
if (!this._options.aotSupport) {
return rawBrowserOptions;
}
const tmpNgsscEnvironmentFilePath = path.join(this._context.workspaceRoot, this._tmpNgsscEnvironmentFile);
const ngsscEnvironmentFileContent = await readFileAsync(this._ngsscEnvironmentFile, 'utf8');
this._tokenizeResult = this._tokenizer.tokenize(ngsscEnvironmentFileContent, ngsscContext);
await writeFileAsync(tmpNgsscEnvironmentFilePath, this._tokenizeResult.content, 'utf8');
return { ...rawBrowserOptions, fileReplacements: this._buildFileReplacements(rawBrowserOptions) };
}
_buildFileReplacements(rawBrowserOptions) {
const fileReplacements = (rawBrowserOptions.fileReplacements || [])
.map(f => 'with' in f ? { ...f } : { replace: f.src, with: f.replaceWith })
.filter(f => f.with === this._options.ngsscEnvironmentFile)
.map(f => ({ replace: f.replace, with: this._tmpNgsscEnvironmentFile }));
if (!fileReplacements.length) {
throw new Error(`Expected a fileReplacements entry in the referenced browserTarget '${this._options.browserTarget}'` +
`, which uses ${this._options.ngsscEnvironmentFile} as a replacement! (e.g. "fileReplacements": ` +
`[{ "replace": "src/environments/environment.ts", "with": "${this._options.ngsscEnvironmentFile}" }])`);
}
return fileReplacements;
}
async _buildNgsscJson(ngsscContext, browserOptions) {
const outputPath = path.join(this._context.workspaceRoot, browserOptions.outputPath);
const ngssc = {
environmentVariables: [
...ngsscContext.variables.map(m => m.variable),
...(this._options.additionalEnvironmentVariables || []),
],
filePattern: this._options.filePattern || path.basename(browserOptions.index),
variant: ngsscContext.variant,
};
await writeFileAsync(path.join(outputPath, 'ngssc.json'), JSON.stringify(ngssc, null, 2), 'utf8');
}
async _untokenize(browserOptions) {
if (!this._tokenizeResult) {
return;
}
const outputPath = path.join(this._context.workspaceRoot, browserOptions.outputPath);
const files = await readdirAsync(outputPath);
for (const file of files
.filter(f => f.endsWith('.js'))
.map(f => path.join(outputPath, f))) {
const fileContent = await readFileAsync(file, 'utf8');
const newFileContent = this._tokenizeResult.untokenize(fileContent);
if (fileContent !== newFileContent) {
await writeFileAsync(file, newFileContent, 'utf8');
}
}
}
async _removeTmpNgsscEnvironmentFile() {
const tmpNgsscEnvironmentFilePath = path.join(this._context.workspaceRoot, this._tmpNgsscEnvironmentFile);
if (fs.existsSync(tmpNgsscEnvironmentFilePath)) {
await unlinkAsync(tmpNgsscEnvironmentFilePath);
}
}
}
var index = architect.createBuilder(async (options, context) => await new NgsscBuilder(options, context).run());
module.exports = index;

4

builders/ngsscbuild/schema.json

@@ -11,3 +11,5 @@ {

"type": "boolean",
"description": "Whether variables are going to be used in AoT contexts (like forRoot(...) or forChild(...))"
"description": "Whether variables are going to be used in AoT contexts (like forRoot(...) or forChild(...))",
"x-deprecated": true,
"default": false
},

@@ -14,0 +16,0 @@ "browserTarget": {

@@ -5,2 +5,10 @@ # Changelog

## [9.0.0-next.0](https://github.com/kyubisation/angular-server-side-configuration/compare/v8.2.1...v9.0.0-next.0) (2020-02-01)
### Features
* make insert commands idempotent ([3c55e34](https://github.com/kyubisation/angular-server-side-configuration/commit/3c55e34eb210033b976c4a8208023d8ef98580f6))
* upgrade to angular 9-rc ([f948ae5](https://github.com/kyubisation/angular-server-side-configuration/commit/f948ae5d5e5085bda112ffa77f9ee5f43713628d))
### [8.2.1](https://github.com/kyubisation/angular-server-side-configuration/compare/v8.2.0...v8.2.1) (2020-01-23)

@@ -7,0 +15,0 @@

@@ -46,13 +46,4 @@ {

"pattern": "^(.*)$"
},
"insertInHead": {
"$id": "#/properties/insertInHead",
"type": "boolean",
"title": "The Insertinhead Schema",
"default": false,
"examples": [
false
]
}
}
}
{
"name": "angular-server-side-configuration",
"version": "8.2.1",
"version": "9.0.0-next.0",
"description": "Configure an angular application on the server",
"publishConfig": {
"tag": "next"
},
"builders": "./builders/builders.json",

@@ -12,3 +15,3 @@ "schematics": "./schematics/collection.json",

"clean": "rimraf coverage dist {builders,models,schematics,src}/**/*.{d.ts,js} test/*.{d.ts,js} junit.xml",
"build:node": "npm run clean && tsc && rollup -c rollup.config.js",
"build:node": "npm run clean && rollup -c rollup.config.js",
"build:go": "docker-compose run build-go",

@@ -25,3 +28,3 @@ "build": "run-p build:*",

"module": "./src/module.js",
"typings": "./src/index.d.ts",
"typings": "./src/module.d.ts",
"files": [

@@ -53,24 +56,24 @@ "**/*.{js,d.ts,json}",

"devDependencies": {
"@angular-devkit/architect": "^0.800.0",
"@angular-devkit/core": "^8.0.0",
"@angular-devkit/schematics": "^8.0.0",
"@schematics/angular": "^8.0.0",
"@angular-devkit/architect": "~0.900.0-rc.11",
"@angular-devkit/core": "^9.0.0-rc.11",
"@angular-devkit/schematics": "^9.0.0-rc.11",
"@schematics/angular": "^9.0.0-rc.11",
"@types/glob-to-regexp": "^0.4.0",
"@types/jest": "^24.0.15",
"@types/node": "^10.14.4",
"@types/rimraf": "^2.0.2",
"@types/jest": "^24.9.1",
"@types/node": "^10.17.14",
"@types/rimraf": "^2.0.3",
"@wessberg/rollup-plugin-ts": "^1.2.15",
"glob-to-regexp": "^0.4.1",
"jest": "^24.8.0",
"jest": "^24.9.0",
"jest-junit": "^6.4.0",
"npm-run-all": "^4.1.5",
"rimraf": "^2.6.3",
"rollup": "^1.17.0",
"rollup-plugin-commonjs": "^10.0.1",
"rimraf": "^2.7.1",
"rollup": "^1.30.1",
"rollup-plugin-commonjs": "^10.1.0",
"rollup-plugin-node-resolve": "^5.2.0",
"rollup-plugin-typescript2": "^0.22.0",
"standard-version": "^7.0.1",
"ts-jest": "^24.0.2",
"ts-node": "^8.3.0",
"tslint": "^5.18.0",
"typescript": "~3.4.3"
"standard-version": "^7.1.0",
"ts-jest": "^24.3.0",
"ts-node": "^8.6.2",
"tslint": "^5.20.1",
"typescript": "~3.6.4"
},

@@ -77,0 +80,0 @@ "jest": {

@@ -24,3 +24,3 @@ # angular-server-side-configuration

## Version 8 Rewrite
Version 8.x of this package is a complete rewrite with Angular schematics and builders.
Version 8.x of this package was a complete rewrite with Angular schematics and builders.
If you require support for older Angular versions,

@@ -30,2 +30,7 @@ [Version 2.x](https://www.npmjs.com/package/angular-server-side-configuration/v/2.0.0)

## Version 9 Change
Version 9 of angular-server-side-configuration deprecates aotSupport, since it is
no longer required for Angular 9 with Ivy. The update schematic removes the option
from your angular.json.
## Getting Started

@@ -68,7 +73,7 @@ ```

"additionalEnvironmentVariables": ["MANUAL_ENTRIES"],
"aotSupport": true, // Set this to true, if you need to use
// environment variables inside AoT contexts
// (e.g. forRoot(...) or forChild(...))
"browserTarget": "your-project-name:build",
"ngsscEnvironmentFile": "src/environments/environment.prod.ts"
"ngsscEnvironmentFile": "src/environments/environment.prod.ts",
// Optional
// (Defaults to the basename of the index option of the browser target)
"filePattern": "index.html"
},

@@ -170,3 +175,3 @@ "configurations": {

FROM nginx:alpine
ADD https://github.com/kyubisation/angular-server-side-configuration/releases/download/v8.0.0/ngssc_64bit /usr/sbin/ngssc
ADD https://github.com/kyubisation/angular-server-side-configuration/releases/download/v9.0.0-next.0/ngssc_64bit /usr/sbin/ngssc
RUN chmod +x /usr/sbin/ngssc

@@ -173,0 +178,0 @@ COPY dist /usr/share/nginx/html

@@ -1,7 +0,28 @@

import { tmpdir } from 'os';
import commonjs from 'rollup-plugin-commonjs';
import resolve from 'rollup-plugin-node-resolve';
import typescript from 'rollup-plugin-typescript2';
import ts from "@wessberg/rollup-plugin-ts";
import { join } from 'path';
export default {
export default ['./builders/ngsscbuild', './schematics/ng-add', './schematics/ng-update'].map(p => ({
input: join(p, 'index.ts'),
output: {
file: join(p, 'index.js'),
format: 'cjs'
},
external: [
'@angular-devkit/architect',
'@angular-devkit/core',
'@angular-devkit/schematics',
'@schematics/angular/utility/change',
'@schematics/angular/utility/config',
'crypto',
'fs',
'path',
'util',
'typescript'
],
plugins: [
ts({ browserslist: false })
]
})).concat({
input: './src/index.ts',

@@ -23,9 +44,6 @@ output: [

plugins: [
typescript({
tsconfigOverride: { compilerOptions: { module: 'ESNext', declaration: false } },
cacheRoot: `${tmpdir()}/.rpt2_cache_ngssc`,
}),
ts({ browserslist: false }),
resolve(),
commonjs()
]
}
});

@@ -8,4 +8,9 @@ {

"factory": "./ng-update/index#updateToV8"
},
"migration-v9": {
"version": "9-next",
"description": "Updates angular-server-side-configuration to v9",
"factory": "./ng-update/index#updateToV9"
}
}
}
import { Rule } from '@angular-devkit/schematics';
import { Schema } from './schema';
export default function (options: Schema): Rule;
interface Schema {
additionalEnvironmentVariables: string;
/** Name of the project. */
project: string;
variant: "process" | "NG_ENV";
ngsscEnvironmentFile: string;
}
declare function indexFunc(options: Schema): Rule;
export { indexFunc as default };

@@ -1,9 +0,10 @@

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const core_1 = require("@angular-devkit/core");
const schematics_1 = require("@angular-devkit/schematics");
const change_1 = require("@schematics/angular/utility/change");
const config_1 = require("@schematics/angular/utility/config");
function default_1(options) {
return schematics_1.chain([
'use strict';
var core = require('@angular-devkit/core');
var schematics = require('@angular-devkit/schematics');
var change = require('@schematics/angular/utility/change');
var config = require('@schematics/angular/utility/config');
function index (options) {
return schematics.chain([
addNgsscTargetToWorkspace(options),

@@ -15,3 +16,2 @@ addImportAndDescriptionToEnvironmentFile(options),

}
exports.default = default_1;
function addNgsscTargetToWorkspace(options) {

@@ -22,3 +22,3 @@ return (host, context) => {

context.logger.info(`Skipping adding ngsscbuild target to angular.json, as it already exists in project ${projectName}.`);
return schematics_1.noop();
return schematics.noop();
}

@@ -30,3 +30,2 @@ architect.ngsscbuild = {

? options.additionalEnvironmentVariables.split(',').map(e => e.trim()) : [],
aotSupport: options.aotSupport,
browserTarget: `${projectName}:build`,

@@ -42,3 +41,3 @@ ngsscEnvironmentFile: options.ngsscEnvironmentFile,

};
return config_1.updateWorkspace(workspace);
return config.updateWorkspace(workspace);
};

@@ -49,6 +48,6 @@ }

const { projectRoot } = resolveWorkspace(options, host);
const normalizedPath = core_1.join(core_1.normalize(projectRoot), options.ngsscEnvironmentFile);
const normalizedPath = core.join(core.normalize(projectRoot), options.ngsscEnvironmentFile);
const file = host.get(normalizedPath);
if (!file) {
throw new schematics_1.SchematicsException(`${normalizedPath} does not exist!`);
throw new schematics.SchematicsException(`${normalizedPath} does not exist!`);
}

@@ -81,3 +80,3 @@ else if (file.content.includes('angular-server-side-configuration')) {

`;
const insertion = new change_1.InsertChange(file.path, 0, insertContent);
const insertion = new change.InsertChange(file.path, 0, insertContent);
const recorder = host.beginUpdate(file.path);

@@ -94,3 +93,3 @@ recorder.insertLeft(insertion.pos, insertion.toAdd);

if (buffer === null) {
throw new schematics_1.SchematicsException('Could not find package.json');
throw new schematics.SchematicsException('Could not find package.json');
}

@@ -111,3 +110,3 @@ const pkg = { scripts: {}, ...JSON.parse(buffer.toString()) };

if (!build) {
throw new schematics_1.SchematicsException(`Expected a build target in project ${projectName}!`);
throw new schematics.SchematicsException(`Expected a build target in project ${projectName}!`);
}

@@ -117,3 +116,3 @@ const indexPath = build.options.index || 'src/index.html';

if (!indexHtml) {
throw new schematics_1.SchematicsException(`Expected index html ${indexPath} to exist!`);
throw new schematics.SchematicsException(`Expected index html ${indexPath} to exist!`);
}

@@ -127,3 +126,3 @@ const indexHtmlContent = indexHtml.content.toString();

? indexHtmlContent.indexOf('</title>') + 9 : indexHtmlContent.indexOf('</head>');
const insertion = new change_1.InsertChange(indexHtml.path, insertIndex, ' <!--CONFIG-->\n');
const insertion = new change.InsertChange(indexHtml.path, insertIndex, ' <!--CONFIG-->\n');
const recorder = host.beginUpdate(indexHtml.path);

@@ -135,9 +134,11 @@ recorder.insertLeft(insertion.pos, insertion.toAdd);

function resolveWorkspace(options, host) {
const workspace = config_1.getWorkspace(host);
const workspace = config.getWorkspace(host);
const projectName = options.project || workspace.defaultProject || Object.keys(workspace.projects)[0];
const { architect, root } = workspace.projects[projectName];
if (!architect) {
throw new schematics_1.SchematicsException(`Expected project ${projectName} to have an architect section!`);
throw new schematics.SchematicsException(`Expected project ${projectName} to have an architect section!`);
}
return { workspace, projectName, architect, projectRoot: root };
}
module.exports = index;

@@ -39,8 +39,2 @@ {

},
"aotSupport": {
"description": "Whether variables are going to be used in AoT contexts (like forRoot(...) or forChild(...))",
"type": "boolean",
"default": true,
"x-prompt": "Are variables going to be used in AoT contexts (like forRoot(...) or forChild(...)):"
},
"additionalEnvironmentVariables": {

@@ -47,0 +41,0 @@ "description": "Additional environment variables that should be added to ngssc.json",

import { Rule } from '@angular-devkit/schematics';
export declare function updateToV8(): Rule;
declare function updateToV8(): Rule;
declare function updateToV9(): Rule;
export { updateToV8, updateToV9 };

@@ -1,9 +0,135 @@

"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const schematics_1 = require("@angular-devkit/schematics");
const config_1 = require("@schematics/angular/utility/config");
const index_1 = __importDefault(require("../ng-add/index"));
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var schematics = require('@angular-devkit/schematics');
var config = require('@schematics/angular/utility/config');
var core = require('@angular-devkit/core');
var change = require('@schematics/angular/utility/change');
function ngAdd (options) {
return schematics.chain([
addNgsscTargetToWorkspace(options),
addImportAndDescriptionToEnvironmentFile(options),
addNgsscToPackageScripts(options),
addPlaceholderToIndexHtml(options),
]);
}
function addNgsscTargetToWorkspace(options) {
return (host, context) => {
const { workspace, projectName, architect } = resolveWorkspace(options, host);
if ('ngsscbuild' in architect) {
context.logger.info(`Skipping adding ngsscbuild target to angular.json, as it already exists in project ${projectName}.`);
return schematics.noop();
}
architect.ngsscbuild = {
builder: 'angular-server-side-configuration:ngsscbuild',
options: {
additionalEnvironmentVariables: options.additionalEnvironmentVariables
? options.additionalEnvironmentVariables.split(',').map(e => e.trim()) : [],
browserTarget: `${projectName}:build`,
ngsscEnvironmentFile: options.ngsscEnvironmentFile,
},
// tslint:disable-next-line: object-literal-sort-keys
configurations: {
production: {
browserTarget: `${projectName}:build:production`,
},
},
};
return config.updateWorkspace(workspace);
};
}
function addImportAndDescriptionToEnvironmentFile(options) {
return (host, context) => {
const { projectRoot } = resolveWorkspace(options, host);
const normalizedPath = core.join(core.normalize(projectRoot), options.ngsscEnvironmentFile);
const file = host.get(normalizedPath);
if (!file) {
throw new schematics.SchematicsException(`${normalizedPath} does not exist!`);
}
else if (file.content.includes('angular-server-side-configuration')) {
context.logger.info(`Skipping adding import to ${file.path}, since import was already detected.`);
return;
}
const importExpression = options.variant === 'NG_ENV'
? `import { NG_ENV } from 'angular-server-side-configuration/ng-env';`
: `import 'angular-server-side-configuration/process';`;
const variant = options.variant === 'NG_ENV' ? 'NG_ENV' : 'process.env';
const insertContent = `${importExpression}
/**
* How to use angular-server-side-configuration:
*
* Use ${variant}.NAME_OF_YOUR_ENVIRONMENT_VARIABLE
*
* export const environment = {
* stringValue: ${variant}.STRING_VALUE,
* stringValueWithDefault: ${variant}.STRING_VALUE || 'defaultValue',
* numberValue: Number(${variant}.NUMBER_VALUE),
* numberValueWithDefault: Number(${variant}.NUMBER_VALUE || 10),
* booleanValue: Boolean(${variant}.BOOLEAN_VALUE),
* booleanValueInverted: ${variant}.BOOLEAN_VALUE_INVERTED !== 'false',
* };
*/
`;
const insertion = new change.InsertChange(file.path, 0, insertContent);
const recorder = host.beginUpdate(file.path);
recorder.insertLeft(insertion.pos, insertion.toAdd);
host.commitUpdate(recorder);
};
}
function addNgsscToPackageScripts(options) {
return (host, context) => {
const { projectName } = resolveWorkspace(options, host);
const pkgPath = '/package.json';
const buffer = host.read(pkgPath);
if (buffer === null) {
throw new schematics.SchematicsException('Could not find package.json');
}
const pkg = { scripts: {}, ...JSON.parse(buffer.toString()) };
if ('build:ngssc' in pkg.scripts) {
context.logger.info(`Skipping adding script to package.json, as it already exists.`);
return;
}
pkg.scripts['build:ngssc'] = `ng run ${projectName}:ngsscbuild:production`;
host.overwrite(pkgPath, JSON.stringify(pkg, null, 2));
};
}
function addPlaceholderToIndexHtml(options) {
return (host, context) => {
const { architect, projectName } = resolveWorkspace(options, host);
const build = architect.build;
if (!build) {
throw new schematics.SchematicsException(`Expected a build target in project ${projectName}!`);
}
const indexPath = build.options.index || 'src/index.html';
const indexHtml = host.get(indexPath);
if (!indexHtml) {
throw new schematics.SchematicsException(`Expected index html ${indexPath} to exist!`);
}
const indexHtmlContent = indexHtml.content.toString();
if (/<!--\s*CONFIG\s*-->/.test(indexHtmlContent)) {
context.logger.info(`Skipping adding placeholder to ${indexHtml.path}, as it already contains it.`);
return;
}
const insertIndex = indexHtmlContent.includes('</title>')
? indexHtmlContent.indexOf('</title>') + 9 : indexHtmlContent.indexOf('</head>');
const insertion = new change.InsertChange(indexHtml.path, insertIndex, ' <!--CONFIG-->\n');
const recorder = host.beginUpdate(indexHtml.path);
recorder.insertLeft(insertion.pos, insertion.toAdd);
host.commitUpdate(recorder);
};
}
function resolveWorkspace(options, host) {
const workspace = config.getWorkspace(host);
const projectName = options.project || workspace.defaultProject || Object.keys(workspace.projects)[0];
const { architect, root } = workspace.projects[projectName];
if (!architect) {
throw new schematics.SchematicsException(`Expected project ${projectName} to have an architect section!`);
}
return { workspace, projectName, architect, projectRoot: root };
}
const NGSSC_JSON_PATH = '/ngssc.json';

@@ -14,6 +140,5 @@ function updateToV8() {

const variant = findAndPatchVariantFromFiles(tree);
return schematics_1.chain([
index_1.default({
return schematics.chain([
ngAdd({
additionalEnvironmentVariables: (ngssc.environmentVariables || []).join(','),
aotSupport: true,
ngsscEnvironmentFile: 'src/environments/environment.prod.ts',

@@ -28,3 +153,25 @@ project: '',

}
exports.updateToV8 = updateToV8;
function updateToV9() {
return (tree, context) => {
const workspace = config.getWorkspace(tree);
context.logger.info(`Removing ngsscbuild entry 'aotSupport', since it is no longer necessary for Ivy.`);
Object.keys(workspace.projects)
.filter(p => workspace.projects[p].architect &&
workspace.projects[p].architect.ngsscbuild)
.forEach(p => {
const ngsscbuild = workspace.projects[p].architect.ngsscbuild;
if ('aotSupport' in ngsscbuild.options) {
delete ngsscbuild.options.aotSupport;
context.logger.info(` - Removed from ${p} ngsscbuild options`);
}
Object.keys(ngsscbuild.configurations || {})
.filter(c => 'aotSupport' in ngsscbuild.configurations[c])
.forEach(c => {
delete ngsscbuild.configurations[c].aotSupport;
context.logger.info(` - Removed from ${p} ngsscbuild configuration ${c}`);
});
});
return config.updateWorkspace(workspace);
};
}
function tryReadNgsscJson(tree) {

@@ -74,3 +221,3 @@ const ngssc = tree.read(NGSSC_JSON_PATH);

}
const workspace = config_1.getWorkspace(tree);
const workspace = config.getWorkspace(tree);
const projectName = workspace.defaultProject || Object.keys(workspace.projects)[0];

@@ -81,1 +228,4 @@ context.logger.info('Please remove the ngssc usage from your scripts.');

}
exports.updateToV8 = updateToV8;
exports.updateToV9 = updateToV9;

@@ -183,7 +183,10 @@ 'use strict';

`(function(self){self.process=${JSON.stringify({ env: populatedVariables })};})(window)`;
return `<script>${iife}</script>`;
return `<!--ngssc--><script>${iife}</script><!--/ngssc-->`;
}
function insertIntoHtml(file, iife) {
const fileContent = fs.readFileSync(file, 'utf8');
if (/<!--\s*CONFIG\s*-->/.test(fileContent)) {
if (/<!--ngssc-->[\w\W]*<!--\/ngssc-->/.test(fileContent)) {
fs.writeFileSync(file, fileContent.replace(/<!--ngssc-->[\w\W]*<!--\/ngssc-->/, iife), 'utf8');
}
else if (/<!--\s*CONFIG\s*-->/.test(fileContent)) {
fs.writeFileSync(file, fileContent.replace(/<!--\s*CONFIG\s*-->/, iife), 'utf8');

@@ -190,0 +193,0 @@ }

@@ -179,7 +179,10 @@ import { readdirSync, lstatSync, existsSync, readFileSync, writeFileSync } from 'fs';

`(function(self){self.process=${JSON.stringify({ env: populatedVariables })};})(window)`;
return `<script>${iife}</script>`;
return `<!--ngssc--><script>${iife}</script><!--/ngssc-->`;
}
function insertIntoHtml(file, iife) {
const fileContent = readFileSync(file, 'utf8');
if (/<!--\s*CONFIG\s*-->/.test(fileContent)) {
if (/<!--ngssc-->[\w\W]*<!--\/ngssc-->/.test(fileContent)) {
writeFileSync(file, fileContent.replace(/<!--ngssc-->[\w\W]*<!--\/ngssc-->/, iife), 'utf8');
}
else if (/<!--\s*CONFIG\s*-->/.test(fileContent)) {
writeFileSync(file, fileContent.replace(/<!--\s*CONFIG\s*-->/, iife), 'utf8');

@@ -186,0 +189,0 @@ }