36 Commits

Author SHA1 Message Date
James M. Greene
c5a3e1159e Merge pull request #43 from actions/warn-unsupported-exts
Warn about unsupported file extensions after erring
2022-11-23 09:32:16 -06:00
James M. Greene
a069fede0c Update distributables after updating deps 2022-11-22 23:17:34 -06:00
James M. Greene
2f460cfbe0 Update distributables 2022-11-22 23:11:12 -06:00
James M. Greene
e5c1ee9f14 Reformat 2022-11-22 23:10:56 -06:00
James M. Greene
7fea7010df Minor revisions 2022-11-22 23:10:56 -06:00
James M. Greene
34521f23a5 Add warn for unsupported extensions 2022-11-22 23:10:37 -06:00
James M. Greene
d84b27279d Merge pull request #42 from actions/JamesMGreene-patch-1
Update to the latest `actions/publish-action`
2022-11-22 22:29:53 -06:00
James M. Greene
5650def507 Update to the latest actions/publish-action
To avoid Actions core deprecation messages.

https://github.com/actions/publish-action/releases/tag/v0.2.1
2022-11-22 22:29:07 -06:00
James M. Greene
0c2178e929 Merge pull request #41 from actions/alt-blank-extensions
Test: Better support alternative file extensions for blank config files
2022-11-22 21:35:02 -06:00
James M. Greene
948e60fb96 Reformat 2022-11-22 21:34:10 -06:00
James M. Greene
1305a1ba92 Better support alternative file extensions for blank config files in the tests 2022-11-22 21:30:53 -06:00
James M. Greene
b94e9adb36 Merge pull request #38 from actions/support-wrapped-exports
Support wrapped exports
2022-11-21 16:57:31 -06:00
James M. Greene
fc8c2c4e6e Update the distributables 2022-11-21 13:12:55 -06:00
James M. Greene
e978eba337 Add support for indirect config declarator in chained declaration statement 2022-11-21 13:12:45 -06:00
James M. Greene
343cb08233 Add tests for when multiple declarations are chained together 2022-11-21 12:36:09 -06:00
James M. Greene
f87a94c875 Update the distributables 2022-11-21 12:15:34 -06:00
James M. Greene
7eb40247a7 Format 2022-11-21 12:14:59 -06:00
James M. Greene
86f141f32d Add support for 'Indirect module export with a wrapping call at the export' 2022-11-21 12:12:47 -06:00
James M. Greene
76b6a8292e Small corrections 2022-11-21 12:08:39 -06:00
James M. Greene
8e221f24db Add support for 'Indirect module export with a wrapping call at the definition' 2022-11-21 12:05:26 -06:00
James M. Greene
d897860efd Add support for 'Indirect default export with a wrapping call at the export' 2022-11-21 11:34:58 -06:00
James M. Greene
24270f0cca Add support for 'Indirect default export with a wrapping call at the definition' 2022-11-21 11:04:42 -06:00
James M. Greene
0c3c14948a Merge branch 'main' into support-wrapped-exports 2022-11-18 01:02:58 -06:00
James M. Greene
b0c19d0de9 Merge pull request #37 from actions/merge-pr-33
Merge PR #33
2022-11-18 01:01:12 -06:00
James M. Greene
51323db177 Fix the Next.js tests 2022-11-18 00:57:58 -06:00
James M. Greene
3d9811d6e2 Update distributables 2022-11-18 00:56:40 -06:00
James M. Greene
9c3b6344a2 Merge branch 'main' into patch-1 2022-11-18 00:50:11 -06:00
James M. Greene
97fb35057c Add comment 2022-11-18 00:50:00 -06:00
James M. Greene
c917d1c3cd Merge pull request #35 from actions/bump-actions
Bump actions
2022-11-18 00:46:30 -06:00
James M. Greene
ffa824f004 Start making some of those tests pass 2022-11-18 00:45:01 -06:00
James M. Greene
d4a76d1ee1 Add unit tests to verify support for function-wrapped exports 2022-11-18 00:29:31 -06:00
Yoann Chaudet
bd8a5da49f Bump actions 2022-10-31 16:34:08 -07:00
Kapil Koju
5cb77813a2 Add back experimental.images.unoptimized for old NextJS 2022-10-24 23:46:06 -04:00
Kapil Koju
2094727a1b Fix nextjs images.unoptimized config path name
`images.unoptimized` is no longer in `experimental` and is stable with NextJS `v12.3.0`.
https://nextjs.org/docs/api-reference/next/image#unoptimized
2022-10-24 23:09:43 -04:00
Mingzi
d875fa8dc1 Merge pull request #31 from rentziass/rentziass/update-actions-core
Update @actions/core to 1.10.0
2022-10-06 09:56:39 -07:00
Francesco Renzi
67f329fcfd Update @actions/core to 1.10.0 2022-10-06 11:08:55 +01:00
14 changed files with 589 additions and 112 deletions

View File

@@ -11,7 +11,7 @@ jobs:
draft-release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- uses: release-drafter/release-drafter@v5
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -24,7 +24,7 @@ jobs:
steps:
- name: Update the ${{ env.TAG_NAME }} tag
id: update-major-tag
uses: actions/publish-action@v0.1.0
uses: actions/publish-action@v0.2.1
with:
source-tag: ${{ env.TAG_NAME }}
slack-webhook: ${{ secrets.SLACK_WEBHOOK }}

299
dist/index.js vendored
View File

@@ -140,7 +140,6 @@ const file_command_1 = __nccwpck_require__(717);
const utils_1 = __nccwpck_require__(5278);
const os = __importStar(__nccwpck_require__(2037));
const path = __importStar(__nccwpck_require__(1017));
const uuid_1 = __nccwpck_require__(5840);
const oidc_utils_1 = __nccwpck_require__(8041);
/**
* The code to exit an action
@@ -170,20 +169,9 @@ function exportVariable(name, val) {
process.env[name] = convertedVal;
const filePath = process.env['GITHUB_ENV'] || '';
if (filePath) {
const delimiter = `ghadelimiter_${uuid_1.v4()}`;
// These should realistically never happen, but just in case someone finds a way to exploit uuid generation let's not allow keys or values that contain the delimiter.
if (name.includes(delimiter)) {
throw new Error(`Unexpected input: name should not contain the delimiter "${delimiter}"`);
}
if (convertedVal.includes(delimiter)) {
throw new Error(`Unexpected input: value should not contain the delimiter "${delimiter}"`);
}
const commandValue = `${name}<<${delimiter}${os.EOL}${convertedVal}${os.EOL}${delimiter}`;
file_command_1.issueCommand('ENV', commandValue);
}
else {
command_1.issueCommand('set-env', { name }, convertedVal);
return file_command_1.issueFileCommand('ENV', file_command_1.prepareKeyValueMessage(name, val));
}
command_1.issueCommand('set-env', { name }, convertedVal);
}
exports.exportVariable = exportVariable;
/**
@@ -201,7 +189,7 @@ exports.setSecret = setSecret;
function addPath(inputPath) {
const filePath = process.env['GITHUB_PATH'] || '';
if (filePath) {
file_command_1.issueCommand('PATH', inputPath);
file_command_1.issueFileCommand('PATH', inputPath);
}
else {
command_1.issueCommand('add-path', {}, inputPath);
@@ -241,7 +229,10 @@ function getMultilineInput(name, options) {
const inputs = getInput(name, options)
.split('\n')
.filter(x => x !== '');
return inputs;
if (options && options.trimWhitespace === false) {
return inputs;
}
return inputs.map(input => input.trim());
}
exports.getMultilineInput = getMultilineInput;
/**
@@ -274,8 +265,12 @@ exports.getBooleanInput = getBooleanInput;
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function setOutput(name, value) {
const filePath = process.env['GITHUB_OUTPUT'] || '';
if (filePath) {
return file_command_1.issueFileCommand('OUTPUT', file_command_1.prepareKeyValueMessage(name, value));
}
process.stdout.write(os.EOL);
command_1.issueCommand('set-output', { name }, value);
command_1.issueCommand('set-output', { name }, utils_1.toCommandValue(value));
}
exports.setOutput = setOutput;
/**
@@ -404,7 +399,11 @@ exports.group = group;
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function saveState(name, value) {
command_1.issueCommand('save-state', { name }, value);
const filePath = process.env['GITHUB_STATE'] || '';
if (filePath) {
return file_command_1.issueFileCommand('STATE', file_command_1.prepareKeyValueMessage(name, value));
}
command_1.issueCommand('save-state', { name }, utils_1.toCommandValue(value));
}
exports.saveState = saveState;
/**
@@ -470,13 +469,14 @@ var __importStar = (this && this.__importStar) || function (mod) {
return result;
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.issueCommand = void 0;
exports.prepareKeyValueMessage = exports.issueFileCommand = void 0;
// We use any as a valid input type
/* eslint-disable @typescript-eslint/no-explicit-any */
const fs = __importStar(__nccwpck_require__(7147));
const os = __importStar(__nccwpck_require__(2037));
const uuid_1 = __nccwpck_require__(5840);
const utils_1 = __nccwpck_require__(5278);
function issueCommand(command, message) {
function issueFileCommand(command, message) {
const filePath = process.env[`GITHUB_${command}`];
if (!filePath) {
throw new Error(`Unable to find environment variable for file command ${command}`);
@@ -488,7 +488,22 @@ function issueCommand(command, message) {
encoding: 'utf8'
});
}
exports.issueCommand = issueCommand;
exports.issueFileCommand = issueFileCommand;
function prepareKeyValueMessage(key, value) {
const delimiter = `ghadelimiter_${uuid_1.v4()}`;
const convertedValue = utils_1.toCommandValue(value);
// These should realistically never happen, but just in case someone finds a
// way to exploit uuid generation let's not allow keys or values that contain
// the delimiter.
if (key.includes(delimiter)) {
throw new Error(`Unexpected input: name should not contain the delimiter "${delimiter}"`);
}
if (convertedValue.includes(delimiter)) {
throw new Error(`Unexpected input: value should not contain the delimiter "${delimiter}"`);
}
return `${key}<<${delimiter}${os.EOL}${convertedValue}${os.EOL}${delimiter}`;
}
exports.prepareKeyValueMessage = prepareKeyValueMessage;
//# sourceMappingURL=file-command.js.map
/***/ }),
@@ -15256,7 +15271,7 @@ Pages's path based routing (and work).
Supported configuration initializations:
(1) Default export:
(1) Direct default export:
export default {
// configuration object here
@@ -15268,19 +15283,69 @@ Supported configuration initializations:
// configuration object here
}
(3) Indirect module export:
(3) Indirect default export:
const config = // configuration object here
const config = {
// configuration object here
}
export default config
(4) Indirect module export:
const config = {
// configuration object here
}
module.exports = config
(5) Direct default export with wrapping call:
export default defineConfig({
// configuration object here
})
(6) Direct module export with wrapping call:
module.exports = defineConfig({
// configuration object here
})
(7) Indirect default export with wrapping call at the definition:
const config = defineConfig({
// configuration object here
})
export default config
(8) Indirect default export with wrapping call at the export:
const config = {
// configuration object here
}
export default defineConfig(config)
(9) Indirect module export with wrapping call at the definition:
const config = defineConfig({
// configuration object here
})
module.exports = config
(10) Indirect module export with wrapping call at the export:
const config = {
// configuration object here
}
module.exports = defineConfig(config)
*/
class ConfigParser {
// Ctor
// - configurationFile: path to the configuration file
// - blankConfigurationFile: a blank configuration file to use if non was previously found
constructor({ configurationFile, blankConfigurationFile, properties }) {
constructor({ configurationFile, blankConfigurationFile, allowWrappingCall = false, properties }) {
// Save field
this.configurationFile = configurationFile
this.allowWrappingCall = allowWrappingCall === true
this.properties = properties
// If the configuration file does not exist, initialize it with the blank configuration file
@@ -15296,12 +15361,43 @@ class ConfigParser {
this.configuration = fs.readFileSync(this.configurationFile, 'utf8')
}
findTopLevelVariableDeclarator(ast, identifierName) {
let targetDeclarator
ast.body.find(
node =>
node.type === 'VariableDeclaration' &&
node.declarations &&
node.declarations.length > 0 &&
node.declarations.find(declarator => {
if (
declarator.type === 'VariableDeclarator' &&
declarator.id &&
declarator.id.type === 'Identifier' &&
declarator.id.name === identifierName
) {
targetDeclarator = declarator
return true
}
})
)
return targetDeclarator
}
// Find the configuration object in an AST.
// Look for a default export, a direct module export or an indirect module
// export (in that order).
// Look for, in order:
// - a direct default export
// - a direct default export with a wrapping call
// - an indirect default export
// - an indirect default export with a wrapping call at the definition
// - an indirect default export with a wrapping call at the export
// - a direct module export
// - a direct module export with a wrapping call
// - an indirect module export
// - an indirect module export with a wrapping call at the definition
// - an indirect module export with a wrapping call at the export
//
// Return the configuration object or null.
findConfigurationObject(ast) {
findConfigurationObject(ast, allowWrappingCall = false) {
// Try to find a default export
var defaultExport = ast.body.find(node => node.type === 'ExportDefaultDeclaration')
@@ -15311,21 +15407,61 @@ class ConfigParser {
return defaultExport.declaration
}
// Direct default export with a wrapping call
else if (
allowWrappingCall &&
defaultExport &&
defaultExport.declaration.type === 'CallExpression' &&
defaultExport.declaration.arguments.length > 0 &&
defaultExport.declaration.arguments[0] &&
defaultExport.declaration.arguments[0].type === 'ObjectExpression'
) {
core.info('Found configuration object in direct default export declaration with a wrapping call')
return defaultExport.declaration.arguments[0]
}
// Indirect default export
else if (defaultExport && defaultExport.declaration.type === 'Identifier') {
const identifierName = defaultExport.declaration.name
const identifierDefinition = ast.body.find(
node =>
node.type === 'VariableDeclaration' &&
node.declarations.length == 1 &&
node.declarations[0].type === 'VariableDeclarator' &&
node.declarations[0].id.type === 'Identifier' &&
node.declarations[0].id.name === identifierName &&
node.declarations[0].init.type === 'ObjectExpression'
)
if (identifierDefinition) {
const identifierDeclarator = this.findTopLevelVariableDeclarator(ast, identifierName)
const identifierInitialization = identifierDeclarator && identifierDeclarator.init
if (identifierInitialization && identifierInitialization.type === 'ObjectExpression') {
core.info('Found configuration object in indirect default export declaration')
return identifierDefinition.declarations[0].init
return identifierInitialization
}
// Indirect default export with a wrapping call at the definition
else if (
allowWrappingCall &&
identifierInitialization &&
identifierInitialization.type === 'CallExpression' &&
identifierInitialization.arguments.length > 0 &&
identifierInitialization.arguments[0] &&
identifierInitialization.arguments[0].type === 'ObjectExpression'
) {
core.info(
'Found configuration object in indirect default export declaration with a wrapping call at the definition'
)
return identifierInitialization.arguments[0]
}
}
// Indirect default export with a wrapping call at the export
else if (
allowWrappingCall &&
defaultExport &&
defaultExport.declaration.type === 'CallExpression' &&
defaultExport.declaration.arguments.length > 0 &&
defaultExport.declaration.arguments[0] &&
defaultExport.declaration.arguments[0].type === 'Identifier'
) {
const identifierName = defaultExport.declaration.arguments[0].name
const identifierDeclarator = this.findTopLevelVariableDeclarator(ast, identifierName)
const identifierInitialization = identifierDeclarator && identifierDeclarator.init
if (identifierInitialization && identifierInitialization.type === 'ObjectExpression') {
core.info(
'Found configuration object in indirect default export declaration with a wrapping call at the export'
)
return identifierInitialization
}
}
@@ -15348,21 +15484,57 @@ class ConfigParser {
return moduleExport.expression.right
}
// Direct default export with a wrapping call
else if (
allowWrappingCall &&
moduleExport &&
moduleExport.expression.right.type === 'CallExpression' &&
moduleExport.expression.right.arguments.length > 0 &&
moduleExport.expression.right.arguments[0] &&
moduleExport.expression.right.arguments[0].type === 'ObjectExpression'
) {
core.info('Found configuration object in direct module export with a wrapping call')
return moduleExport.expression.right.arguments[0]
}
// Indirect module export
else if (moduleExport && moduleExport.expression.right.type === 'Identifier') {
const identifierName = moduleExport && moduleExport.expression.right.name
const identifierDefinition = ast.body.find(
node =>
node.type === 'VariableDeclaration' &&
node.declarations.length == 1 &&
node.declarations[0].type === 'VariableDeclarator' &&
node.declarations[0].id.type === 'Identifier' &&
node.declarations[0].id.name === identifierName &&
node.declarations[0].init.type === 'ObjectExpression'
)
if (identifierDefinition) {
const identifierDeclarator = this.findTopLevelVariableDeclarator(ast, identifierName)
const identifierInitialization = identifierDeclarator && identifierDeclarator.init
if (identifierInitialization && identifierInitialization.type === 'ObjectExpression') {
core.info('Found configuration object in indirect module export')
return identifierDefinition.declarations[0].init
return identifierInitialization
}
// Indirect module export with a wrapping call at the definition
else if (
allowWrappingCall &&
identifierInitialization &&
identifierInitialization.type === 'CallExpression' &&
identifierInitialization.arguments.length > 0 &&
identifierInitialization.arguments[0] &&
identifierInitialization.arguments[0].type === 'ObjectExpression'
) {
core.info('Found configuration object in indirect module export with a wrapping call at the definition')
return identifierInitialization.arguments[0]
}
}
// Indirect module export with a wrapping call at the export
else if (
allowWrappingCall &&
moduleExport &&
moduleExport.expression.right.type === 'CallExpression' &&
moduleExport.expression.right.arguments.length > 0 &&
moduleExport.expression.right.arguments[0] &&
moduleExport.expression.right.arguments[0].type === 'Identifier'
) {
const identifierName = moduleExport.expression.right.arguments[0].name
const identifierDeclarator = this.findTopLevelVariableDeclarator(ast, identifierName)
const identifierInitialization = identifierDeclarator && identifierDeclarator.init
if (identifierInitialization && identifierInitialization.type === 'ObjectExpression') {
core.info('Found configuration object in indirect module export declaration with a wrapping call at the export')
return identifierInitialization
}
}
@@ -15426,7 +15598,7 @@ class ConfigParser {
const ast = espree.parse(this.configuration, espreeOptions)
// Find the configuration object
var configurationObject = this.findConfigurationObject(ast)
var configurationObject = this.findConfigurationObject(ast, this.allowWrappingCall)
if (!configurationObject) {
throw 'Could not find a configuration object in the configuration file'
}
@@ -15600,6 +15772,8 @@ const core = __nccwpck_require__(2186)
const { ConfigParser } = __nccwpck_require__(8395)
const removeTrailingSlash = __nccwpck_require__(9255)
const SUPPORTED_FILE_EXTENSIONS = ['.js', '.cjs', '.mjs']
// Return the settings to be passed to a {ConfigParser} for a given static site generator,
// optional configuration file path, and a Pages siteUrl value to inject
function getConfigParserSettings({ staticSiteGenerator, generatorConfigFile, siteUrl }) {
@@ -15632,7 +15806,9 @@ function getConfigParserSettings({ staticSiteGenerator, generatorConfigFile, sit
// Disable server side image optimization too
// https://nextjs.org/docs/api-reference/next/image#unoptimized
'experimental.images.unoptimized': true
'experimental.images.unoptimized': true,
// No longer experimental as of Next.js v12.3.0
'images.unoptimized': true
}
}
case 'gatsby':
@@ -15672,11 +15848,22 @@ function setPagesConfig({ staticSiteGenerator, generatorConfigFile, siteUrl }) {
const settings = getConfigParserSettings({ staticSiteGenerator, generatorConfigFile, siteUrl })
new ConfigParser(settings).injectAll()
} catch (error) {
const isSupportedFileExtension = SUPPORTED_FILE_EXTENSIONS.some(ext => generatorConfigFile.endsWith(ext))
// Logging
core.warning(
`We were unable to determine how to inject the site metadata into your config. Generated URLs may be incorrect. The base URL for this site should be ${siteUrl}. Please ensure your framework is configured to generate relative links appropriately.`,
error
)
if (!isSupportedFileExtension) {
core.warning(
`Unsupported configuration file extension. Currently supported extensions: ${SUPPORTED_FILE_EXTENSIONS.map(
ext => JSON.stringify(ext)
).join(', ')}`,
error
)
} else {
core.warning(
`We were unable to determine how to inject the site metadata into your config. Generated URLs may be incorrect. The base URL for this site should be ${siteUrl}. Please ensure your framework is configured to generate relative links appropriately.`,
error
)
}
}
}

2
dist/index.js.map vendored

File diff suppressed because one or more lines are too long

14
package-lock.json generated
View File

@@ -9,7 +9,7 @@
"version": "1.0.0",
"license": "MIT",
"dependencies": {
"@actions/core": "^1.9.1",
"@actions/core": "^1.10.0",
"axios": "^0.27.2",
"espree": "^9.3.2"
},
@@ -23,9 +23,9 @@
}
},
"node_modules/@actions/core": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.9.1.tgz",
"integrity": "sha512-5ad+U2YGrmmiw6du20AQW5XuWo7UKN2052FjSV7MX+Wfjf8sCqcsZe62NfgHys4QI4/Y+vQvLKYL8jWtA1ZBTA==",
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.10.0.tgz",
"integrity": "sha512-2aZDDa3zrrZbP5ZYg159sNoLRb61nQ7awl5pSvIq5Qpj81vwDzdMRKzkWJGJuwVvWpvZKx7vspJALyvaaIQyug==",
"dependencies": {
"@actions/http-client": "^2.0.1",
"uuid": "^8.3.2"
@@ -5747,9 +5747,9 @@
},
"dependencies": {
"@actions/core": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.9.1.tgz",
"integrity": "sha512-5ad+U2YGrmmiw6du20AQW5XuWo7UKN2052FjSV7MX+Wfjf8sCqcsZe62NfgHys4QI4/Y+vQvLKYL8jWtA1ZBTA==",
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.10.0.tgz",
"integrity": "sha512-2aZDDa3zrrZbP5ZYg159sNoLRb61nQ7awl5pSvIq5Qpj81vwDzdMRKzkWJGJuwVvWpvZKx7vspJALyvaaIQyug==",
"requires": {
"@actions/http-client": "^2.0.1",
"uuid": "^8.3.2"

View File

@@ -24,7 +24,7 @@
},
"homepage": "https://github.com/actions/configure-pages#readme",
"dependencies": {
"@actions/core": "^1.9.1",
"@actions/core": "^1.10.0",
"axios": "^0.27.2",
"espree": "^9.3.2"
},

View File

@@ -9,7 +9,7 @@ Pages's path based routing (and work).
Supported configuration initializations:
(1) Default export:
(1) Direct default export:
export default {
// configuration object here
@@ -21,19 +21,69 @@ Supported configuration initializations:
// configuration object here
}
(3) Indirect module export:
(3) Indirect default export:
const config = // configuration object here
const config = {
// configuration object here
}
export default config
(4) Indirect module export:
const config = {
// configuration object here
}
module.exports = config
(5) Direct default export with wrapping call:
export default defineConfig({
// configuration object here
})
(6) Direct module export with wrapping call:
module.exports = defineConfig({
// configuration object here
})
(7) Indirect default export with wrapping call at the definition:
const config = defineConfig({
// configuration object here
})
export default config
(8) Indirect default export with wrapping call at the export:
const config = {
// configuration object here
}
export default defineConfig(config)
(9) Indirect module export with wrapping call at the definition:
const config = defineConfig({
// configuration object here
})
module.exports = config
(10) Indirect module export with wrapping call at the export:
const config = {
// configuration object here
}
module.exports = defineConfig(config)
*/
class ConfigParser {
// Ctor
// - configurationFile: path to the configuration file
// - blankConfigurationFile: a blank configuration file to use if non was previously found
constructor({ configurationFile, blankConfigurationFile, properties }) {
constructor({ configurationFile, blankConfigurationFile, allowWrappingCall = false, properties }) {
// Save field
this.configurationFile = configurationFile
this.allowWrappingCall = allowWrappingCall === true
this.properties = properties
// If the configuration file does not exist, initialize it with the blank configuration file
@@ -49,12 +99,43 @@ class ConfigParser {
this.configuration = fs.readFileSync(this.configurationFile, 'utf8')
}
findTopLevelVariableDeclarator(ast, identifierName) {
let targetDeclarator
ast.body.find(
node =>
node.type === 'VariableDeclaration' &&
node.declarations &&
node.declarations.length > 0 &&
node.declarations.find(declarator => {
if (
declarator.type === 'VariableDeclarator' &&
declarator.id &&
declarator.id.type === 'Identifier' &&
declarator.id.name === identifierName
) {
targetDeclarator = declarator
return true
}
})
)
return targetDeclarator
}
// Find the configuration object in an AST.
// Look for a default export, a direct module export or an indirect module
// export (in that order).
// Look for, in order:
// - a direct default export
// - a direct default export with a wrapping call
// - an indirect default export
// - an indirect default export with a wrapping call at the definition
// - an indirect default export with a wrapping call at the export
// - a direct module export
// - a direct module export with a wrapping call
// - an indirect module export
// - an indirect module export with a wrapping call at the definition
// - an indirect module export with a wrapping call at the export
//
// Return the configuration object or null.
findConfigurationObject(ast) {
findConfigurationObject(ast, allowWrappingCall = false) {
// Try to find a default export
var defaultExport = ast.body.find(node => node.type === 'ExportDefaultDeclaration')
@@ -64,21 +145,61 @@ class ConfigParser {
return defaultExport.declaration
}
// Direct default export with a wrapping call
else if (
allowWrappingCall &&
defaultExport &&
defaultExport.declaration.type === 'CallExpression' &&
defaultExport.declaration.arguments.length > 0 &&
defaultExport.declaration.arguments[0] &&
defaultExport.declaration.arguments[0].type === 'ObjectExpression'
) {
core.info('Found configuration object in direct default export declaration with a wrapping call')
return defaultExport.declaration.arguments[0]
}
// Indirect default export
else if (defaultExport && defaultExport.declaration.type === 'Identifier') {
const identifierName = defaultExport.declaration.name
const identifierDefinition = ast.body.find(
node =>
node.type === 'VariableDeclaration' &&
node.declarations.length == 1 &&
node.declarations[0].type === 'VariableDeclarator' &&
node.declarations[0].id.type === 'Identifier' &&
node.declarations[0].id.name === identifierName &&
node.declarations[0].init.type === 'ObjectExpression'
)
if (identifierDefinition) {
const identifierDeclarator = this.findTopLevelVariableDeclarator(ast, identifierName)
const identifierInitialization = identifierDeclarator && identifierDeclarator.init
if (identifierInitialization && identifierInitialization.type === 'ObjectExpression') {
core.info('Found configuration object in indirect default export declaration')
return identifierDefinition.declarations[0].init
return identifierInitialization
}
// Indirect default export with a wrapping call at the definition
else if (
allowWrappingCall &&
identifierInitialization &&
identifierInitialization.type === 'CallExpression' &&
identifierInitialization.arguments.length > 0 &&
identifierInitialization.arguments[0] &&
identifierInitialization.arguments[0].type === 'ObjectExpression'
) {
core.info(
'Found configuration object in indirect default export declaration with a wrapping call at the definition'
)
return identifierInitialization.arguments[0]
}
}
// Indirect default export with a wrapping call at the export
else if (
allowWrappingCall &&
defaultExport &&
defaultExport.declaration.type === 'CallExpression' &&
defaultExport.declaration.arguments.length > 0 &&
defaultExport.declaration.arguments[0] &&
defaultExport.declaration.arguments[0].type === 'Identifier'
) {
const identifierName = defaultExport.declaration.arguments[0].name
const identifierDeclarator = this.findTopLevelVariableDeclarator(ast, identifierName)
const identifierInitialization = identifierDeclarator && identifierDeclarator.init
if (identifierInitialization && identifierInitialization.type === 'ObjectExpression') {
core.info(
'Found configuration object in indirect default export declaration with a wrapping call at the export'
)
return identifierInitialization
}
}
@@ -101,21 +222,57 @@ class ConfigParser {
return moduleExport.expression.right
}
// Direct default export with a wrapping call
else if (
allowWrappingCall &&
moduleExport &&
moduleExport.expression.right.type === 'CallExpression' &&
moduleExport.expression.right.arguments.length > 0 &&
moduleExport.expression.right.arguments[0] &&
moduleExport.expression.right.arguments[0].type === 'ObjectExpression'
) {
core.info('Found configuration object in direct module export with a wrapping call')
return moduleExport.expression.right.arguments[0]
}
// Indirect module export
else if (moduleExport && moduleExport.expression.right.type === 'Identifier') {
const identifierName = moduleExport && moduleExport.expression.right.name
const identifierDefinition = ast.body.find(
node =>
node.type === 'VariableDeclaration' &&
node.declarations.length == 1 &&
node.declarations[0].type === 'VariableDeclarator' &&
node.declarations[0].id.type === 'Identifier' &&
node.declarations[0].id.name === identifierName &&
node.declarations[0].init.type === 'ObjectExpression'
)
if (identifierDefinition) {
const identifierDeclarator = this.findTopLevelVariableDeclarator(ast, identifierName)
const identifierInitialization = identifierDeclarator && identifierDeclarator.init
if (identifierInitialization && identifierInitialization.type === 'ObjectExpression') {
core.info('Found configuration object in indirect module export')
return identifierDefinition.declarations[0].init
return identifierInitialization
}
// Indirect module export with a wrapping call at the definition
else if (
allowWrappingCall &&
identifierInitialization &&
identifierInitialization.type === 'CallExpression' &&
identifierInitialization.arguments.length > 0 &&
identifierInitialization.arguments[0] &&
identifierInitialization.arguments[0].type === 'ObjectExpression'
) {
core.info('Found configuration object in indirect module export with a wrapping call at the definition')
return identifierInitialization.arguments[0]
}
}
// Indirect module export with a wrapping call at the export
else if (
allowWrappingCall &&
moduleExport &&
moduleExport.expression.right.type === 'CallExpression' &&
moduleExport.expression.right.arguments.length > 0 &&
moduleExport.expression.right.arguments[0] &&
moduleExport.expression.right.arguments[0].type === 'Identifier'
) {
const identifierName = moduleExport.expression.right.arguments[0].name
const identifierDeclarator = this.findTopLevelVariableDeclarator(ast, identifierName)
const identifierInitialization = identifierDeclarator && identifierDeclarator.init
if (identifierInitialization && identifierInitialization.type === 'ObjectExpression') {
core.info('Found configuration object in indirect module export declaration with a wrapping call at the export')
return identifierInitialization
}
}
@@ -179,7 +336,7 @@ class ConfigParser {
const ast = espree.parse(this.configuration, espreeOptions)
// Find the configuration object
var configurationObject = this.findConfigurationObject(ast)
var configurationObject = this.findConfigurationObject(ast, this.allowWrappingCall)
if (!configurationObject) {
throw 'Could not find a configuration object in the configuration file'
}

View File

@@ -10,7 +10,7 @@ const tempFolder = getTempFolder()
// Cases to test
const cases = [
//
// Default export
// Direct default export
//
{
property: 'property',
@@ -97,11 +97,13 @@ const cases = [
source: 'const config = {}; export default config',
expected: 'const config = { property: "value"}; export default config'
},
// with more than 1 declaration chained together
{
property: 'property',
source: 'var config = {}; export default config',
expected: 'var config = { property: "value"}; export default config'
source: 'var temp = {}, config = {}; export default config',
expected: 'var temp = {}, config = { property: "value"}; export default config'
},
// deeper
{
property: 'a.b.c',
source: 'var config = {}; export default config',
@@ -140,11 +142,13 @@ const cases = [
source: 'const config = {}; module.exports = config',
expected: 'const config = { property: "value"}; module.exports = config'
},
// with more than 1 declaration chained together
{
property: 'property',
source: 'var config = {}; module.exports = config',
expected: 'var config = { property: "value"}; module.exports = config'
source: 'var temp = {}, config = {}; module.exports = config',
expected: 'var temp = {}, config = { property: "value"}; module.exports = config'
},
// deeper
{
property: 'a.b.c',
source: 'var config = {}; module.exports = config',
@@ -154,6 +158,109 @@ const cases = [
property: 'a.b.c',
source: 'var config = { a: { b: [], c: "hello" } }; module.exports = config',
expected: 'var config = { a: { b: { c: "value"}, c: "hello" } }; module.exports = config'
},
//
// Direct default export with wrapping call
//
{
property: 'property',
source: 'import { defineConfig } from "astro/config"; export default defineConfig({ p1: 0 })',
expected: 'import { defineConfig } from "astro/config"; export default defineConfig({ property: "value", p1: 0 })',
allowWrappingCall: true
},
//
// Direct module exports with wrapping call
//
{
property: 'property',
source: 'const { defineConfig } = require("astro/config"); module.exports = defineConfig({ p1: 0 })',
expected:
'const { defineConfig } = require("astro/config"); module.exports = defineConfig({ property: "value", p1: 0 })',
allowWrappingCall: true
},
//
// Indirect default export with wrapping call at the definition
//
{
property: 'property',
source: 'import { defineConfig } from "astro/config"; const config = defineConfig({}); export default config',
expected:
'import { defineConfig } from "astro/config"; const config = defineConfig({ property: "value" }); export default config',
allowWrappingCall: true
},
// with more than 1 declaration chained together
{
property: 'property',
source:
'import { defineConfig } from "astro/config"; const temp = {}, config = defineConfig({}); export default config',
expected:
'import { defineConfig } from "astro/config"; const temp = {}, config = defineConfig({ property: "value" }); export default config',
allowWrappingCall: true
},
//
// Indirect default export with wrapping call at the export
//
{
property: 'property',
source: 'import { defineConfig } from "astro/config"; const config = {}; export default defineConfig(config)',
expected:
'import { defineConfig } from "astro/config"; const config = { property: "value" }; export default defineConfig(config)',
allowWrappingCall: true
},
// with more than 1 declaration chained together
{
property: 'property',
source:
'import { defineConfig } from "astro/config"; const temp = {}, config = {}; export default defineConfig(config)',
expected:
'import { defineConfig } from "astro/config"; const temp = {}, config = { property: "value" }; export default defineConfig(config)',
allowWrappingCall: true
},
//
// Indirect module exports with wrapping call at the definition
//
{
property: 'property',
source:
'const { defineConfig } = require("astro/config"); const config = defineConfig({}); module.exports = config',
expected:
'const { defineConfig } = require("astro/config"); const config = defineConfig({ property: "value"}); module.exports = config',
allowWrappingCall: true
},
// with more than 1 declaration chained together
{
property: 'property',
source:
'const { defineConfig } = require("astro/config"); const temp = {}, config = defineConfig({}); module.exports = config',
expected:
'const { defineConfig } = require("astro/config"); const temp = {}, config = defineConfig({ property: "value"}); module.exports = config',
allowWrappingCall: true
},
//
// Indirect module exports with wrapping call at the export
//
{
property: 'property',
source:
'const { defineConfig } = require("astro/config"); const config = {}; module.exports = defineConfig(config)',
expected:
'const { defineConfig } = require("astro/config"); const config = { property: "value"}; module.exports = defineConfig(config)',
allowWrappingCall: true
},
// with more than 1 declaration chained together
{
property: 'property',
source:
'const { defineConfig } = require("astro/config"); const temp = {}, config = {}; module.exports = defineConfig(config)',
expected:
'const { defineConfig } = require("astro/config"); const temp = {}, config = { property: "value"}; module.exports = defineConfig(config)',
allowWrappingCall: true
}
]
@@ -168,7 +275,7 @@ describe('config-parser', () => {
jest.spyOn(core, 'debug').mockImplementation(jest.fn())
})
cases.forEach(({ property, source, expected }, index) => {
cases.forEach(({ property, source, expected, allowWrappingCall = false }, index) => {
it(`injects path properly for case #${index}`, () => {
// Write the source file
const sourceFile = `${tempFolder}/source.js`
@@ -180,7 +287,8 @@ describe('config-parser', () => {
// Update the settings and do the injection
new ConfigParser({
configurationFile: sourceFile
configurationFile: sourceFile,
allowWrappingCall
}).inject(property, 'value')
// Compare the files

View File

@@ -1,3 +1,3 @@
// Default Pages configuration for Next
const nextConfig = { experimental: { images: { unoptimized: true } }, basePath: '/docs' }
const nextConfig = { images: { unoptimized: true }, experimental: { images: { unoptimized: true } }, basePath: '/docs' }
module.exports = nextConfig

View File

@@ -1,5 +1,6 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
images: { unoptimized: true },
experimental: { images: { unoptimized: true } },
basePath: '/docs',
reactStrictMode: true,

View File

@@ -1,5 +1,6 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
images: { unoptimized: true },
experimental: { images: { unoptimized: true } },
basePath: '/docs',
reactStrictMode: true,

View File

@@ -1,5 +1,6 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
images: { unoptimized: true },
experimental: { images: { unoptimized: true } },
basePath: '/docs',
reactStrictMode: true,

View File

@@ -2,6 +2,8 @@ const core = require('@actions/core')
const { ConfigParser } = require('./config-parser')
const removeTrailingSlash = require('./remove-trailing-slash')
const SUPPORTED_FILE_EXTENSIONS = ['.js', '.cjs', '.mjs']
// Return the settings to be passed to a {ConfigParser} for a given static site generator,
// optional configuration file path, and a Pages siteUrl value to inject
function getConfigParserSettings({ staticSiteGenerator, generatorConfigFile, siteUrl }) {
@@ -34,7 +36,9 @@ function getConfigParserSettings({ staticSiteGenerator, generatorConfigFile, sit
// Disable server side image optimization too
// https://nextjs.org/docs/api-reference/next/image#unoptimized
'experimental.images.unoptimized': true
'experimental.images.unoptimized': true,
// No longer experimental as of Next.js v12.3.0
'images.unoptimized': true
}
}
case 'gatsby':
@@ -74,11 +78,22 @@ function setPagesConfig({ staticSiteGenerator, generatorConfigFile, siteUrl }) {
const settings = getConfigParserSettings({ staticSiteGenerator, generatorConfigFile, siteUrl })
new ConfigParser(settings).injectAll()
} catch (error) {
const isSupportedFileExtension = SUPPORTED_FILE_EXTENSIONS.some(ext => generatorConfigFile.endsWith(ext))
// Logging
core.warning(
`We were unable to determine how to inject the site metadata into your config. Generated URLs may be incorrect. The base URL for this site should be ${siteUrl}. Please ensure your framework is configured to generate relative links appropriately.`,
error
)
if (!isSupportedFileExtension) {
core.warning(
`Unsupported configuration file extension. Currently supported extensions: ${SUPPORTED_FILE_EXTENSIONS.map(
ext => JSON.stringify(ext)
).join(', ')}`,
error
)
} else {
core.warning(
`We were unable to determine how to inject the site metadata into your config. Generated URLs may be incorrect. The base URL for this site should be ${siteUrl}. Please ensure your framework is configured to generate relative links appropriately.`,
error
)
}
}
}

View File

@@ -11,6 +11,13 @@ const tempFolder = getTempFolder()
const SUPPORTED_GENERATORS = ['next', 'nuxt', 'gatsby', 'sveltekit']
const SUPPORTED_FILE_EXTENSIONS = ['.js', '.cjs', '.mjs']
const IS_BLANK_CONFIG_FILE_REGEX = new RegExp(
'^blank\\.(' + SUPPORTED_FILE_EXTENSIONS.map(ext => ext.slice(1)).join('|') + ')$'
)
function isBlankConfigFileName(fileName) {
return IS_BLANK_CONFIG_FILE_REGEX.test(fileName)
}
// Test suite
describe('configParser', () => {
@@ -44,7 +51,7 @@ describe('configParser', () => {
// Copy the source fixture to a temp file
const fixtureSourceFile = `${fixtureFolder}/${configurationFile}`
const fixtureTargetFile = `${tempFolder}/${configurationFile}`
if (configurationFile !== 'blank.js') {
if (!isBlankConfigFileName(configurationFile)) {
fs.copyFileSync(fixtureSourceFile, fixtureTargetFile)
} else if (fs.existsSync(fixtureTargetFile)) {
fs.rmSync(fixtureTargetFile)
@@ -77,7 +84,7 @@ describe('configParser', () => {
// Copy the source fixture to a temp file
const fixtureSourceFile = `${fixtureFolder}/${configurationFile}`
const fixtureTargetFile = `${tempFolder}/${configurationFile}`
if (configurationFile !== 'blank.js') {
if (!isBlankConfigFileName(configurationFile)) {
fs.copyFileSync(fixtureSourceFile, fixtureTargetFile)
} else if (fs.existsSync(fixtureTargetFile)) {
fs.rmSync(fixtureTargetFile)